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

服务端:

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

  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

  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. @Configuration
  7. @EnableWebSocketMessageBroker
  8. public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
  9. @Override
  10. public void configureMessageBroker(MessageBrokerRegistry config) {
  11. config.enableSimpleBroker("/topic","/user");
  12. config.setApplicationDestinationPrefixes("/app");
  13. config.setUserDestinationPrefix("/user/");
  14. }
  15. @Override
  16. public void registerStompEndpoints(StompEndpointRegistry registry) {
  17. registry.addEndpoint("/webServer").withSockJS();
  18. }
  19. }

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

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

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

  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. @Controller
  8. public class WebSocketController {
  9. public SimpMessagingTemplate template;
  10. @Autowired
  11. public WebSocketController(SimpMessagingTemplate template) {
  12. this.template = template;
  13. }
  14. @MessageMapping("/hello")
  15. @SendTo("/topic/hello")
  16. public Greeting greeting(Greeting message) throws Exception {
  17. return message;
  18. }
  19. @MessageMapping("/message")
  20. @SendToUser("/message")
  21. public UserMessage userMessage(UserMessage userMessage) throws Exception {
  22. return userMessage;
  23. }
  24. }

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

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

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

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

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

  1. webSocketController.template.convertAndSend("/topic/hello",greeting) //广播
  2. webSocketController.template.convertAndSendToUser(userId, "/message",userMessage) //一对一发送,发送特定的客户端

客户端:

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

  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. stompClient.subscribe('/user/' + userId + '/message', function(message){
  9. var messageEntity = JSON.parse(message.body);
  10. });
  11. });

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

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

spring websocket + stomp 实现广播通信和一对一通信<转>的更多相关文章

  1. spring boot websocket stomp 实现广播通信和一对一通信聊天

    一.前言 玩.net的时候,在asp.net下有一个叫 SignalR 的框架,可以在ASP .NET的Web项目中实现实时通信.刚接触java寻找相关替代品,发现 java 体系中有一套基于stom ...

  2. Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能

    本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自 ...

  3. spring websocket 和socketjs实现单聊群聊,广播的消息推送详解

    spring websocket 和socketjs实现单聊群聊,广播的消息推送详解 WebSocket简单介绍 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随 ...

  4. spring+rabbitmq+stomp搭建websocket消息推送(非spring boot方式)

    前言: 两年前做过spring+activemq+stomp的ws推送,那个做起来很简单,但现在公司用的mq中间件是rabbitmq,因此需要通过rabbitmq去做ws通信.仔细搜了搜百度/谷歌,网 ...

  5. Spring Boot 中使用 WebSocket 实现一对多聊天及一对一聊天

    为什么需要WebSocket? 我们已经有了http协议,为什么还需要另外一个协议?有什么好处? 比如我想得到价格变化,只能是客户端想服务端发起请求,服务器返回结果,HTTP协议做不到服务器主动向客户 ...

  6. java WebSocket的实现以及Spring WebSocket

    开始学习WebSocket,准备用它来实现一个在页面实时输出log4j的日志以及控制台的日志. 首先知道一些基础信息: java7 开始支持WebSocket,并且只是做了定义,并未实现 tomcat ...

  7. spring WebSocket详解

    场景 websocket是Html5新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决http请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天.股票交易.游戏 ...

  8. Spring WebSocket教程(一)

    学习背景 很久以前就知道WebSocket,但那时不论是浏览器还是开发技术对它的支持都还很少.但是,Spring4突然发布,让我眼前一亮,Spring4直接支持WebSocket. 对于Spring我 ...

  9. spring websocket集群问题的简单记录

    目录 前言 解决方案 代码示例 前言 最近公司里遇到一个问题,在集群中一些websocket的消息丢失了. 产生问题的原理很简单,发送消息的服务和接收者连接的服务不是同一个服务. 解决方案 用中间件( ...

随机推荐

  1. cassandra运行出现了Unable to gossip with any seeds,cqlsh链接不上,提示connection refused处理办法

    cassandra运行出现了Unable to gossip with any seeds,cqlsh链接不上,提示connection refused处理办法 问题描述 当启动了cassandra之 ...

  2. linux中WDCP的日志彻底删除技巧

    apache或nginx都有开关默认日志,一个是正常访问日志,一个是错误的日志,目录在 /www/wdlinux/nginx-1.0.15/logs /www/wdlinux/httpd-2.2.22 ...

  3. [转]Java中使用Runtime和Process类运行外部程序

    帖子1: 使用Runtime.getRuntime().exec()方法可以在java程序里运行外部程序.  1. exec(String command)  2. exec(String comma ...

  4. php实现ZIP压缩文件解压缩(转)

    测试使用了两个办法都可以实现: 第一个:需要开启配置php_aip.dll <?php //需开启配置 php_zip.dll //phpinfo(); header("Content ...

  5. django -- 为model 指定数据库名

    一.为model指定数据库名: django自己实现的ORM中.如果要指定一个model的表名是通过Meta类来实现的. from django.db import models # Create y ...

  6. ${HADOOP_CONF_DIR:-$HADOOP_PREFIX/$DEFAULT_CONF_DIR}

      在hadoop-config.sh中,有如下语句:${HADOOP_CONF_DIR:-$HADOOP_PREFIX/$DEFAULT_CONF_DIR}                     ...

  7. /etc/ssh/sshd_config 关建字:PermitRootLogin no  禁示以root身份登录服务器

    这种情况,不会影响,普通用户su到root

  8. 【小白的CFD之旅】24 稳态和瞬态

    小白最近在练习案例的时候,对稳态和瞬态的问题,产生了一些疑问.譬如说,为什么有的案例用稳态,而有的案例用瞬态?有时候相同的案例既可以用稳态也可以用瞬态,而有的案例却只能用瞬态计算?小白决定找小牛师兄问 ...

  9. 每日英语:China to Move Slowly on One-Child Law Reform

    BEIJING—China's family-planning agency is projecting a slow rollout for an easing of its one-child p ...

  10. 【Windows】windows核心编程整理(上)

    小续 这是我11年看<windows核心编程>时所作的一些笔记,现整理出来共享给大家 windows核心编程整理(上) windows核心编程整理(下) 线程的基础知识 进程是不活泼的,进 ...