zoukankan      html  css  js  c++  java
  • spring springboot2 结合 websocket+sockJs+stomp 实现个人订阅和广播模式

    一  名词解释

      1.WebSocket

    WebSocket 是发送和接收消息的底层API,WebSocket 协议提供了通过一个套接字实现全双工通信的功能。也能够实现 web 浏览器和 server 间的异步通信,全双工意味着 server 与浏览器间可以发送和接收消息。需要注意的是必须考虑浏览器是否支持

      2.SockJs

    为了应对许多浏览器不支持WebSocket协议的问题,设计了备选SockJs。

    SockJS 是 WebSocket 技术的一种模拟。SockJS 会 尽可能对应 WebSocket API,但如果 WebSocket 技术不可用的话,就会选择另外的通信方式协议。

      3.STOMP

    SockJS 为 WebSocket 提供了 备选方案。但无论哪种场景,对于实际应用来说,这种通信形式层级过低。下面看一下如何 在 WebSocket 之上使用 STOMP协议,来为浏览器 和 server 间的 通信增加适当的消息语义。(STOMP—— Simple Text Oriented Message Protocol——面向消息的简单文本协议)

      4.三者之间的关系

    WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是 底层协议,而 STOMP 是基于 WebSocket(SockJS) 的上层协议

    二 springboot的config

    <!--  websocket-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>

      1.基础配置

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
    
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            registry.enableSimpleBroker("/topic", "/queue", "/user"); //表示在topic和queue这两个域上服务端可以向客户端发消息
            registry.setApplicationDestinationPrefixes("/app");//客户端向服务器端发送时的主题上面需要加"/app"作为前缀
            registry.setUserDestinationPrefix("/user");//指定用户发送一对一的主题,前缀是"/user"
        }
    
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/stomp/endpoint").withSockJS();
        }
    }

    第一步就是添加注解 此注解 这个配置类不仅配置了 WebSocket,还配置了基于代理的 STOMP 消息

    第二步 配置一个消息代理..一个是允许服务器向客户端发送的域 一个是客户端想服务器发送的前缀,最后一个是指定一对第一发送的前缀

    第三步 就是配置了节点,并且使用sockjs的方式

      2.监听连接与断开

      用到了redis管理session

        @Access(name = "监听websocket连接成功")
        @EventListener
        public void onConnectEvent(SessionConnectEvent event) {
            //获取Session连接信息
            StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
            //获取SessionId
            String sessionId = sha.getSessionId();
            //存储redis
            Map<String, String> map = new HashMap<String, String>();
            map.put(sessionId, agentNo);
            redisTemplate.opsForHash().putAll("webSocket", map);
        }
    
        @Access(name = "监听websocket断开连接")
        @EventListener
        public void onDisconnectEvent(SessionDisconnectEvent event) {
            //获取Session连接信息
            StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
            //获取SessionId
            String sessionId = sha.getSessionId();
            //redis删除此sessionId
            redisTemplate.opsForHash().delete("webSocket", sessionId);
        }
    }
    

      三.实现前端代码

       1.引入js 

    <!-- websocket   ****代表自己的项目路径  这个写自己的  -->
    <script src="/***/sockjs-client/sockjs.min.js"></script>
    <script src="/***/stomp-websocket/stomp.min.js"></script>
    <!-- 参考 -->
    <!-- 
    https://cdn.bootcdn.net/ajax/libs/sockjs-client/1.4.0/sockjs.min.js
    https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.min.js
    -->

      2.连接和订阅消息

      使用了agentNo 区分订阅广播消息与个人消息

    var stompClient = null;
    var socket = null;
    function connect() {
        //从sesionStorage获取坐席工号  下面连接头需要  这个按照自己需求修改
        agentNo = sessionStorage.getItem("agentNo");
        //建立连接对象(还未发起连接)  地址更换成自己的  连接服务器注册端点endPoint时,写访问服务器的全路径URL:
        socket = new SockJS('地址');
        //获取 STOMP 子协议的客户端对象
        stompClient = Stomp.over(socket);
        //建立连接,并且连接头上定义了坐席工号
        stompClient.connect({
            userName: agentNo    // <---这是头 在后面的监听  连接成功的类可以获取到  业务代码需要 按需删除
        }, function (frame) {
            console.log('Connected: ' + frame);
            //订阅广播消息
            stompClient.subscribe('/topic/greetings', function (greeting) {
                var data = JSON.parse(greeting.body).data;
                //实现自己的需求
            });
            //订阅个人消息   
            stompClient.subscribe('/user/' + agentNo + '/message', function (greeting) {
                var data = JSON.parse(greeting.body);
                //实现自己的需求
            });
        });
    }
    

      2.发送消息

    function send(data) {
        var param = {
            id: data,
            release: true
        }
        stompClient.send("/app/release", {}, JSON.stringify(param));  
     // <----- app 就是在config中定义的客户端往服务器发送的前缀,param是信息.必须用实体发送后台必须用实体接收
    //release是后面controller中定义的 相当于RequestMapping中写的地址一样
    }
    

      四.实现后端代码

        1.发送广播

        @Access(name = "发布公告")
        @MessageMapping("/release")
        @SendTo("/topic/greetings")
        public WebResult release(@RequestBody Announcement announcement) {
           //执行业务代码逻辑
        }
    

      2.发送个人消息

        @Autowired
        private SimpMessagingTemplate messagingTemplate;
    
         public void demo() {
         // messagingTemplate.convertAndSend(url,"");  //方法1
        //方法2  相当于/user/' + agentNo + '/message'    对应前端订阅的地址
        messagingTemplate.convertAndSendToUser(ledgerQuery.getAgentNo(), "/message", "");
    }
    

      

     

  • 相关阅读:
    C# Enum转换
    Split
    WCF访问安全
    [转] 检索 COM 类工厂中 CLSID 为 {000209FF00000000C000000000000046} 的组件时失败
    ICSharpCode.SharpZipLib.dll压缩的zip包,7zip解压时出错
    js控制ctrl+p
    跨域访问WCF问题
    sql:过滤字段中是否包含数字
    序列化/反序化
    [转]RegistryKey 操作注册表
  • 原文地址:https://www.cnblogs.com/nuti/p/12931338.html
Copyright © 2011-2022 走看看