zoukankan      html  css  js  c++  java
  • spring websocket + stomp 实现广播通信和一对一通信<转>

    spring对于基于stomp协议的websocket通信,其官网上面有一个guide,但是根据guide你只能写出来广播方式的通信,不能实现一对一的通信,这篇文章在这里把广播和一对一一起整理一下给大家。

    服务端:

    一,依赖,spring-websocket和spring-messaging,这里给出maven方式:

    [html] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. <dependency>  
    2.             <groupId>org.springframework</groupId>  
    3.             <artifactId>spring-websocket</artifactId>  
    4.             <version>${spring-core.version}</version>  
    5.         </dependency>  
    6.         <dependency>  
    7.             <groupId>org.springframework</groupId>  
    8.             <artifactId>spring-messaging</artifactId>  
    9.             <version>${spring-core.version}</version>  
    10.         </dependency>  


    二,服务端代码:

    服务端的初始化,只需要两个类:WebsocketConfig和WebSocketController

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. import org.springframework.context.annotation.Configuration;  
    2. import org.springframework.messaging.simp.config.MessageBrokerRegistry;  
    3. import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;  
    4. import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;  
    5. import org.springframework.web.socket.config.annotation.StompEndpointRegistry;  
    6.   
    7. @Configuration  
    8. @EnableWebSocketMessageBroker  
    9. public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {  
    10.   
    11.     @Override  
    12.     public void configureMessageBroker(MessageBrokerRegistry config) {  
    13.         config.enableSimpleBroker("/topic","/user");  
    14.         config.setApplicationDestinationPrefixes("/app");  
    15.         config.setUserDestinationPrefix("/user/");  
    16.     }  
    17.   
    18.     @Override  
    19.     public void registerStompEndpoints(StompEndpointRegistry registry) {  
    20.         registry.addEndpoint("/webServer").withSockJS();  
    21.     }  
    22.   
    23. }  

    这个类表示启用websocket消息处理,以及收发消息的域

    config.enableSimpleBroker("/topic","/user");这句表示在topic和user这两个域上可以向客户端发消息;config.setUserDestinationPrefix("/user/");这句表示给指定用户发送(一对一)的主题前缀是“/user/”;  config.setApplicationDestinationPrefixes("/app"); 这句表示客户端向服务端发送时的主题上面需要加"/app"作为前缀;registry.addEndpoint("/webServer").withSockJS();这个和客户端创建连接时的url有关,后面在客户端的代码中可以看到。


    下面是一个spring风格的controller,用于接收客户端的消息及响应客户端:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. import org.springframework.beans.factory.annotation.Autowired;  
    2. import org.springframework.messaging.handler.annotation.MessageMapping;  
    3. import org.springframework.messaging.handler.annotation.SendTo;  
    4. import org.springframework.messaging.simp.SimpMessagingTemplate;  
    5. import org.springframework.messaging.simp.annotation.SendToUser;  
    6. import org.springframework.stereotype.Controller;  
    7.   
    8. @Controller  
    9. public class WebSocketController {  
    10.   
    11.     public SimpMessagingTemplate template;  
    12.   
    13.     @Autowired  
    14.     public WebSocketController(SimpMessagingTemplate template) {  
    15.         this.template = template;  
    16.     }  
    17.   
    18.     @MessageMapping("/hello")  
    19.     @SendTo("/topic/hello")  
    20.     public Greeting greeting(Greeting message) throws Exception {  
    21.         return message;  
    22.     }  
    23.   
    24.     @MessageMapping("/message")  
    25.     @SendToUser("/message")  
    26.     public UserMessage userMessage(UserMessage userMessage) throws Exception {  
    27.         return userMessage;  
    28.     }  
    29.   
    30. }  

    这个类里面织入SimpMessagingTemplate对象,后面动态发送消息时,需要用到这个对象。

    第一个方法,表示服务端可以接收客户端通过主题“/app/hello”发送过来的消息,客户端需要在主题"/topic/hello"上监听并接收服务端发回的消息

    第二个方法道理相同,只是注意这里用的是@SendToUser,这就是发送给单一客户端的标志。本例中,客户端接收一对一消息的主题应该是“/user/” + 用户Id + “/message” ,这里的用户id可以是一个普通的字符串,只要每个用户端都使用自己的id并且服务端知道每个用户的id就行。

    这里的Greeting和UserMessage是一个普通的实现了序列化的Java bean

    就这样,那么,在程序中的其他地方要动态发送消息,就是下面这两句代码:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. webSocketController.template.convertAndSend("/topic/hello",greeting) //广播  
    2. webSocketController.template.convertAndSendToUser(userId, "/message",userMessage) //一对一发送,发送特定的客户端  
    
    
    

    客户端:

    js客户端需要导入两个js组件:sockjs-0.3.4.js,stomp.js

    [javascript] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. var url = 'http://localhost:8080/appRoot/webServer'  
    2. var socket = new SockJS(url, undefined, {protocols_whitelist: ['websocket']});  
    3. var stompClient = Stomp.over(socket);  
    4. stompClient.connect({}, function(frame) {  
    5.     stompClient.subscribe('/topic/hello', function(message){  
    6.         var json = JSON.parse(message.body);  
    7.     });  
    8.   
    9.      stompClient.subscribe('/user/' + userId + '/message', function(message){  
    10.          var messageEntity = JSON.parse(message.body);  
    11.     });  
    12. });  

    第一个subscribe,是接收广播消息,第二个是接收一对一消息,其主题是'/user/' + userId+ '/message' , 不同客户端具有不同的userId

    看到这里,你会发现,这里所谓的一对一,只是业务层面的一对一,也就是,需要不同客户端具有不同的userId才能实现,如果两个客户端使用相同的userid, 那么服务端给这个userId发送消息时,这两个客户端都会收到。要真正实现websocket技术层面的一对一发送,那就要使用websocket的session了。关于session方式,我这里上传一个demo,有兴趣可以下载:http://download.csdn.net/detail/valenon/8725195

  • 相关阅读:
    LeetCode子集问题
    面试题-求最大字典区间
    链表快速排序
    树的非递归遍历
    快速排序非递归实现
    leetcode217 python3 72ms 存在重复元素
    leetcode121 C++ 12ms 买股票的最佳时机 只能买卖一次
    leetcode1 python3 76ms twoSum 360面试题
    leetcode485 python3 88ms 最大连续1的个数
    leetcode119 C++ 0ms 杨辉三角2
  • 原文地址:https://www.cnblogs.com/winkey4986/p/5622758.html
Copyright © 2011-2022 走看看