开发者

SpringBoot整合WebSocket实现实时通信功能

开发者 https://www.devze.com 2023-11-30 10:27 出处:网络 作者: fking86
目录什么是WebSocket?Spring Boot中的WebSocket支持WebSocket和HTTP优劣势WebSocket的优势:HTTP的优势:示例版本依赖代码测试总结什么是WebSocket?
目录
  • 什么是WebSocket?
  • Spring Boot中的WebSocket支持
  • WebSocket和HTTP优劣势
    • WebSocket的优势:
    • HTTP的优势:
  • 示例
    • 版本依赖
    • 代码
    • 测试
  • 总结

    什么是WebSocket?

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

    Spring Boot中的WebSocket支持

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

    WebSocket和HTTP优劣势

    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<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("toUIDandroid");
                    //传送给对应的toUserId用户的WebSocket
                    if (StringUtils.isNotBlank(toUID) && webSocketMap.containsKey(toUID)) {
                        webSocketMap.get(toUID).sendMsg(objectMapper.writeValueAsString(map));
                    } else {
                        //若果不在这个服务器上,可以考虑发送到mysql或者redis
    python                    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已打开");
            javascript        //socket.send("这是来自客户端的消息" + location.href + new Date());
                };
                //获得消息事件
                socket.onmessage = function (msg) {
               js     console.log(msg.data);
                    //发现消息进入,开始处理前端触发逻辑
                };
                //关闭事件
                socket.onclosPDmkSnlue = 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

    SpringBoot整合WebSocket实现实时通信功能

    第二个:

    http://localhost:8080/socket/page

    SpringBoot整合WebSocket实现实时通信功能

    都点击开启socket

    SpringBoot整合WebSocket实现实时通信功能

    都点击发送

    SpringBoot整合WebSocket实现实时通信功能

    至此示例发送完成

    总结

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

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

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

    以上就是SpringBoot整合WebSocket实现实时通信功能的详细内容,更多关于SpringBoot WebSocket通信的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号