美文网首页
React+Spring-Boot实现WebSocket全双工通

React+Spring-Boot实现WebSocket全双工通

作者: GIT提交不上 | 来源:发表于2019-07-07 23:32 被阅读0次

    一、WebSocket协议

     WebSocket是一种在单个TCP连接上进行全双工通信的协议。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。该协议解决了传统的推送技术(轮询、Comet)的不足,无需不断向服务器发出请求,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。


     浏览器和服务器完成一次握手的示例如下:
     1. 客户端发出请求

    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    Origin: http://example.com
    

     2. 服务器响应

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
    Sec-WebSocket-Protocol: chat
    

    参考链接:维基百科-WebSocket


    1.Stomp协议

     本文使用WebSocket的其中一种实现(STOMP协议)进行代码讲解。

    STOMP即简单流文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。
    参考链接:1)Stomp-官方文档 2)Stomp-中文翻译文档

    二、Spring Boot后端搭建

    1.引入websocket依赖

     由于Spring Boot有封装好的websocket依赖,所以直接在pom.xml导入即可。

            <!--引入websocket依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-websocket</artifactId>
            </dependency>
    

    2.新增websocket配置类

    //import省略
    @Configuration
    @EnableWebSocketMessageBroker //@注解1
    
    //继承WebSocket消息代理的类
    public class WebSocketServerConfig extends AbstractWebSocketMessageBrokerConfigurer {
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/endpoint").setAllowedOrigins("*").withSockJS(); //@注解2
        }
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            //注册广播消息代理和点对点代理
            registry.enableSimpleBroker("/topic", "/queue"); //@注解3
            //设置点对点代理订阅前缀
            registry.setUserDestinationPrefix("/queue"); //@注解4
        }
    }
    
    1. @注解1:开启websocket消息代理,使得控制器支持使用@MessageMapping注解(映射客户端的请求,类似于@RequestMapping)。
    2. @注解2:添加名为endpoint(可自定义)的访问端点,设置允许所有的域名跨域访问并指定使用SockJS协议。
    3. @注解3:注册广播消息代理和点对点代理,广播消息代理名只能为topic(待验证),点对点代理名可以自定义。
    4. @注解4:设置点对点消息代理订阅前缀,默认为点对点代理名。(可以不设置

    3.接受客户端消息&主动发送消息(广播&点对点)

     新增WsController类。

    //import省略
    @Controller
    public class WsController {
    
        private Logger logger = LoggerFactory.getLogger(WsController.class);
    
        @Autowired
        private SimpMessagingTemplate  messagingTemplate; //@注解1
        private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss sss");
        //映射客户端"/hello"请求
        @MessageMapping(value = "/hello") //@注解2
        //向订阅了"/topic/hello"主题的客户端广播消息
        @SendTo(value = "/topic/hello") //@注解3
        public String reponseMsg(String msg) {  //msg->客户端传来的消息
           return msg+"world";
        }
    
        @Scheduled(fixedRate = 1000*10) //设置定时器,每隔10s主动向客户端(订阅了"/topic/hello"主题)发送消息
        @SendTo("/topic/hello")
        public void scheduleSendMsg() {
            Date now = new Date();
            //发送消息
            messagingTemplate.convertAndSend("/topic/hello", df.format(now).toString());//@注解4
            logger.info(now.toString());
        }
        //点对点通信
        @Scheduled(fixedRate = 1000*10)
        public void scheduleSendMsgToUser() {
            Date now = new Date();
            int userId = 1;
            //@注解5
            messagingTemplate.convertAndSendToUser(userId+"","/queue/hello", df.format(now).toString()); 
            logger.info(now.toString());
        }
    
    }
    

    1. @注解1:SpringBoot提供操作WebSocket的对象。
    2. @注解2:客户端请求路径。
    3. @注解3:发送广播消息的订阅主题。
    4. @注解4:向订阅了相同主题的客户端群发消息,convertAndSend(arg1,arg2),参数1为客户端订阅主题(监听通道),参数2为发送的消息实体。
    5. @注解5:点对点发送消息,convertAndSendToUser(arg1,arg2,arg3),参数1为客户端的接受标识,参数2为客户端订阅主题(监听通道),参数3为发送的消息实体。
    6. @Scheduled注解设置定时,为了便于测试,实际使用可以直接调用对应的方法。

    参考链接:
    1.SpringBoot集成WebSocket【基于STOMP协议】进行点对点[一对一]和广播[一对多]实时推送,内附简易聊天室demo
    2.Spring-Boot-WebSocket官方文档


    三.React前端搭建

    1.导入react-stomp依赖

    使用 npm install --save react-stomp 命令下载react-stomp依赖

    2.实现一对多通信

     创建SampleComponent.js

    import React from 'react';
    import SockJsClient from 'react-stomp';
     
    class SampleComponent extends React.Component {
      constructor(props) {
        super(props);
      }
     
      sendMessage = (msg) => {
            this.clientRef.sendMessage('/hello', msg);  //@注解1
      }
     
      render() {
        return (
          <div>
                 <!-- @注解2-->
                 <SockJsClient url='http://localhost:7001/endpoint' topics={['/topic/hello']}
                    onMessage={(msg) => { alert(msg); }}
                    ref={(client) => { this.clientRef = client }} />
          </div>
        );
      }
    }
    export default SampleComponent ;
    

    1. @注解1:客户端向服务器发送消息,sendMessage(arg1,arg2),参数1对应服务器 端@MessageMapping注解的请求路径,参数2为向服务器发送的消息实体。
    2. @注解2:<SockJsClient />,参数url为建立WebSocket连接的地址,endpoint为服务器端设置的访问端点,参数topics为服务器端@SendTo注解设置的订阅主题(监听通道),或者为服务器端convertAndSend()方法中对应的订阅主题(监听通道)。参数onMessage方法为接受服务器端的消息,其msg参数为接受的消息实体。
    3. 向服务器端发送消息只需调用sendMessage函数即可。

    3.实现一对一通信

     创建SampleComponent.js

    import React from 'react';
    import SockJsClient from 'react-stomp';
     
    class SampleComponent extends React.Component {
      constructor(props) {
        super(props);
      }
     
    
      render() {
        return (
          <div>
                 <!-- @注解1-->
                 <SockJsClient url='http://localhost:7001/endpoint' topics={['/queue/1/queue/hello']}
                    onMessage={(msg) => { alert(msg); }}
                    ref={(client) => { this.clientRef = client }} />
          </div>
        );
      }
    }
    export default SampleComponent ;
    

    1. @注解1:<SockJsClient />,参数url、onMessage同【2.实现一对多通信】,参数topics={['/queue/1/queue/hello']},第一个queue为服务器端设置的点对点代理订阅前缀,1为客户端标识,对应于服务器端convertAndSendToUser方法的参数1,"/queue/hello"为服务器端设置点对点订阅主题(监听通道)。

    参考链接:npm-react-stomp说明文档

    四、测试

     测试较为简单,本人在本地测试已通过,故在此省略。

    (待完善,持续更新中,如果有错,欢迎大家留言指正,谢谢!)

    相关文章

      网友评论

          本文标题:React+Spring-Boot实现WebSocket全双工通

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