【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

2024-05-13 1714阅读

文章目录

      • 前言:
      • 什么是WebSocket?
      • Spring Boot中的WebSocket支持
      • WebSocket和HTTP优劣势
        • WebSocket的优势:
          • 1.实时性:
          • 2.较低的延迟:
          • 3.较小的数据传输量:
          • 4.更好的兼容性:
          • HTTP的优势:
            • 1.简单易用:
            • 2.更广泛的应用:
            • 3.更好的安全性:
            • 示例
              • 版本依赖
              • 代码
                • WebSocketConfig
                • WebSocketServer
                • WebSocketController
                • webSocket.html
                • 测试
                  • 打开2个页面
                  • 都点击开启socket
                  • 都点击发送
                  • 总结
                  • 源码获取
                  • 写在最后

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    前言:

                    在当今互联网时代,实时通信已经成为了许多应用程序的基本需求。

                    而WebSocket作为一种全双工通信协议,为开发者提供了一种简单、高效的实时通信解决方案。

                    本文将介绍如何使用Spring Boot框架来实现WebSocket的集成,快速搭建实时通信功能。


                    什么是WebSocket?

                    WebSocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP请求-响应模式不同,WebSocket允许服务器主动向客户端推送数据,实现了实时通信的功能。WebSocket协议基于HTTP协议,通过在握手阶段升级协议,使得服务器和客户端可以直接进行数据交换,而无需频繁的HTTP请求。


                    Spring Boot中的WebSocket支持

                    Spring Boot提供了对WebSocket的支持,通过集成Spring WebSocket模块,我们可以轻松地实现WebSocket功能。在Spring Boot中,我们可以使用注解来定义WebSocket的处理器和消息处理方法,从而实现实时通信。


                    WebSocket和HTTP优劣势

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    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适用于传输各种类型的数据和简单的请求-响应模式。在实际应用中,可以根据具体需求选择合适的协议。


                    示例

                    版本依赖
                    模块版本
                    SpringBoot3.1.0
                    JDK17
                    代码
                    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 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 map = objectMapper.readValue(message, new TypeReference(){});
                                    //追加发送人(防止串改)
                                    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 pushToClient(String message, @PathVariable String toUID) throws Exception {
                            WebSocketServer.sendInfo(message, toUID);
                            return ResponseEntity.ok("Send Success!");
                        }
                    }
                    
                    webSocket.html
                    
                    
                        
                        WebSocket消息通知
                    
                    
                    
                        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() + '"}');
                            }
                        }
                    
                    
                    

                    【uid】:

                    【toUID】:

                    【Msg】:

                    【第一步操作:】: 开启socket

                    【第二步操作:】: 发送消息

                    测试
                    打开2个页面

                    第一个:

                    http://localhost:8080/socket/page

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    第二个:

                    http://localhost:8080/socket/page

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    都点击开启socket

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    都点击发送

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

                    至此示例发送完成


                    总结

                    通过本文的介绍,我们了解了Spring Boot中如何集成WebSocket,实现实时通信的功能。

                    WebSocket作为一种高效的实时通信协议,为开发者提供了更好的用户体验和交互性。

                    希望本文能够帮助快速掌握Spring Boot整合WebSocket的方法,为应用程序添加实时通信功能。


                    源码获取

                    如果需要完整源码请关注公众号"架构殿堂" ,回复 "SpringBoot+WebSocket"即可获得


                    写在最后

                    感谢您的支持和鼓励! 😊🙏

                    如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!

                    【Springboot系列】SpringBoot整合WebSocket,既然如此简单(含源码)

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]