美文网首页
spring boot与websocket的双工异步通信--消息

spring boot与websocket的双工异步通信--消息

作者: KyGb | 来源:发表于2019-08-11 21:42 被阅读0次

    HTTP与websocket协议区别

    HTTP协议的特点

    • [ ] 1.无状态协议
    • [ ] 2.用于通过Internet发送请求消息和响应消息
    • [ ] 3.使用端口接收和发送消息,默认端口80

    缺点:无法直接实现双向通信与消息推送

    WebSocket:
    是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
    特点:

    • [ ] 1.事件驱动
    • [ ] 2.异步
    • [ ] 3.使用ws或者wss协议的客户端socket
      缺点:
      少部分浏览器不支持,浏览器支持的程度与方式有区别。

    1.应用控制层:

    @SpringBootApplication
    @RestController
    public class WebSocketChatApplication {
    
        /**
         * 登陆界面
         */
        @GetMapping("/")
        public ModelAndView login() {
            return new ModelAndView("/login");
        }
    
        /**WebSecurityConfigurerAdapter
         * 聊天界面
         */
        @GetMapping("/index")
        public ModelAndView index(String username, String password, HttpServletRequest request) throws UnknownHostException {
            if (StringUtils.isEmpty(username)) {
                username = "匿名用户";
            }
            ModelAndView mav = new ModelAndView("/chat");
            mav.addObject("username", username);
            //  webSocketUrl -> ws://ip地址:8080/chat
            mav.addObject("webSocketUrl", "ws://"+InetAddress.getLocalHost().getHostAddress()+":"+request.getServerPort()+request.getContextPath()+"/chat");
            return mav;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(WebSocketChatApplication.class, args);
        }
    }
    

    2.WebSocket服务端

    同步方式阻塞式:推送消息给每个会话

    
    /**
     * WebSocket 聊天服务端
     *
     *  ServerEndpoint WebSocket服务端 需指定端点的访问路径
     *  Session   WebSocket会话对象 通过它给客户端发送消息
     */
    @Component
    @ServerEndpoint("/chat")
    public class WebSocketChatServer {
    
        /**
         * 全部在线会话  PS: 基于场景考虑 这里使用线程安全的Map存储会话对象。
         */
        private static Map<String, Session> onlineSessions = new ConcurrentHashMap<>();
    
    
        /**
         * 当客户端打开连接:1.添加会话对象 2.更新在线人数
         */
        @OnOpen
        public void onOpen(Session session) {
            onlineSessions.put(session.getId(), session);
            sendMessageToAll(Message.jsonStr(Message.ENTER, "", "", onlineSessions.size()));
        }
    
        /**
         * 当客户端发送消息:1.获取它的用户名和消息 2.发送消息给所有人
         * <p>
         * PS: 这里约定传递的消息为JSON字符串 方便传递更多参数!
         */
        @OnMessage
        public void onMessage(Session session, String jsonStr) {
            Message message = JSON.parseObject(jsonStr, Message.class);
            sendMessageToAll(Message.jsonStr(Message.SPEAK, message.getUsername(), message.getMsg(), onlineSessions.size()));
        }
    
        /**
         * 当关闭连接:1.移除会话对象 2.更新在线人数
         */
        @OnClose
        public void onClose(Session session) {
            onlineSessions.remove(session.getId());
            sendMessageToAll(Message.jsonStr(Message.QUIT, "", "", onlineSessions.size()));
        }
    
        /**
         * 当通信发生异常:打印错误日志
         */
        @OnError
        public void onError(Session session, Throwable error) {
            error.printStackTrace();
        }
    
        /**
         * 公共方法:发送信息给所有人  
         */
        private static void sendMessageToAll(String msg) {
            onlineSessions.forEach((id, session) -> {
                try {
                    session.getBasicRemote().sendText(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    
    }
    

    3.WebSocket配置

    扫描和注册所有携带ServerEndPoint注解的实例。

    @Configuration
    public class WebSocketConfig {
    
        /**
         * 用于扫描和注册所有携带ServerEndPoint注解的实例。
         * <p>
         * PS:若部署到外部容器 则无需提供此类。
         */
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
    
            return new ServerEndpointExporter();
        }
    
    }
    
    public class Message {
    
        public static final String ENTER = "ENTER";
        public static final String SPEAK = "SPEAK";
        public static final String QUIT = "QUIT";
    
        private String type;//消息类型
    
        private String username; //发送人
    
        private String msg; //发送消息
    
        private int onlineCount; //在线用户数
        }
    

    客户端:

    <script th:inline="javascript">
        /**
         * WebSocket客户端
         *
         * 使用说明:
         * 1、WebSocket客户端通过回调函数来接收服务端消息。例如:webSocket.onmessage
         * 2、WebSocket客户端通过send方法来发送消息给服务端。例如:webSocket.send();
         */
        function getWebSocket() {
            /**
             * WebSocket客户端 PS:URL开头表示WebSocket协议 中间是域名端口 结尾是服务端映射地址
             */
            var webSocket = new WebSocket(/*[[${webSocketUrl}]]*/ 'ws://localhost:8080/chat');
            /**
             * 当服务端打开连接
             */
            webSocket.onopen = function (event) {
                console.log('WebSocket打开连接');
            };
            /**
             * 当服务端发来消息:1.广播消息 2.更新在线人数
             */
            webSocket.onmessage = function (event) {
                console.log('WebSocket收到消息:%c' + event.data, 'color:green');
                //获取服务端消息
                var message = JSON.parse(event.data) || {};
                var $messageContainer = $('.message-container');
    
                if (message.type === 'SPEAK') {
                    $messageContainer.append(
                        '<div class="mdui-card" style="margin: 10px 0;">' +
                        '<div class="mdui-card-primary">' +
                        '<div class="mdui-card-content message-content">' + message.username + ":" + message.msg + '</div>' +
                        '</div></div>');
                }
                $('.chat-num').text(message.onlineCount);
                //防止刷屏
                var $cards = $messageContainer.children('.mdui-card:visible').toArray();
                if ($cards.length > 5) {
                    $cards.forEach(function (item, index) {
                        index < $cards.length - 5 && $(item).slideUp('fast');
                    });
                }
            };
            /**
             * 关闭连接
             */
            webSocket.onclose = function (event) {
                console.log('WebSocket关闭连接');
            };
            /**
             * 通信失败
             */
            webSocket.onerror = function (event) {
                console.log('WebSocket发生异常');
            };
            return webSocket;
        }
        var webSocket = getWebSocket();
        /**
         * 通过WebSocket对象发送消息给服务端
         */
        function sendMsgToServer() {
            var $message = $('#msg');
            if ($message.val()) {
                webSocket.send(JSON.stringify({username: $('#username').text(), msg: $message.val()}));
                $message.val(null);
            }
        }
        /**
         * 清屏
         */
        function clearMsg() {
            $(".message-container").empty();
        }
        /**
         * 使用ENTER发送消息
         */
        document.onkeydown = function (event) {
            var e = event || window.event || arguments.callee.caller.arguments[0];
            e.keyCode === 13 && sendMsgToServer();
        };
    </script>
    

    admin给user发送信息



    user收到信息并回复


    相关文章

      网友评论

          本文标题:spring boot与websocket的双工异步通信--消息

          本文链接:https://www.haomeiwen.com/subject/kncejctx.html