前言:

两年前做过spring+activemq+stomp的ws推送,那个做起来很简单,但现在公司用的mq中间件是rabbitmq,因此需要通过rabbitmq去做ws通信。仔细搜了搜百度/谷歌,网上通过spring boot+rabbitmq+stomp的教程文章倒是一搜一大把,可惜目前的项目是非spring boot的,没法套用。只好自己去捣鼓。搞了几个小时,终于弄出来了,特此与大家分享下。

RabbitMQ:

怎么安装就不是本篇讨论的话题了,自己百度/谷歌之。rabbitmq默认自带了stomp插件,但是需要自己启用。命令为:

rabbitmq-plugins enable rabbitmq_stomp

来来来,给个文档地址参考参考,http://www.rabbitmq.com/stomp.html。默认用guest用户去连接,密码也是guest。

这里有个问题,看rabbitmq配置文件,stomp协议端口默认是61613,但是用ws协议连接却始终连接不上,所以只能用web stomp端口,端口号是15674,这个跟activemq有所区别。(P.S. 此处最好有大神来解惑,或者告知如何用61613来连

Javascript:

前端代码撸起来最方便,关键是调试也容易,因此先来。

var stompClient = null;

var headers = {
login: 'guest',
passcode: 'guest'
}; function wsConnect(url) {
var ws = new SockJS(url);
stompClient = Stomp.over(ws); //var ws = new WebSocket(url);
//stompClient = Stomp.over(ws); // SockJS does not support heart-beat: disable heart-beats
stompClient.heartbeat.outgoing = 0;
stompClient.heartbeat.incoming = 0; stompClient.connect(headers, function (frame) {
console.log('Connected: ' + frame); stompClient.subscribe('/topic/test', function (sms) {
var obj = JSON.parse(sms.body)
var count = obj.totalCount; console.log("count: " + count);
}); });
}

然后就连接呗。

$(function(){
var url = "http://host:15674/stomp";
wsConnect(url);
});

撸完准备测试,当然是选择chrome喽,页面加载后,打开console控制台,可以看到web socket连上了,前端大功告成。

  

Java:

定义一个StompService类专门用来发送stomp消息。注意:rabbitmq 3.7以后stomp插件不再支持sockjs,因此写法会有变化。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport; import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List; /**
* stomp服务 rabbitmq做中间件
* @author Selwyn
* @version $Id: WebSocketConfig.java, v 0.1 9/7/2018 9:59 AM Selwyn Exp $
*/
@Component
public class StompService { private static final String URL_TEMPLATE = "http://%s:%s/stomp"; @Value("${rabbit.host}")
private String host; //@Value("${rabbit.stomp.port}")
private Integer port = 15674; /**
* 连接用户名
*/
//@Value("${rabbit.stomp.login}")
private String login = "guest";
/**
* 连接密码
*/
//@Value("${rabbit.stomp.passCode}")
private String passCode = "guest"; private String url; @PostConstruct
public void init()
{
url = String.format(URL_TEMPLATE, host, port);
} /**
* 发送stomp消息
* @param dest 目的地 比如/topic/test
* @param toSend 要发送的信息
* @param <T>
*/
public <T> void connectAndSend(String dest, T toSend)
{
WebSocketClient client = new StandardWebSocketClient(); List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport( client) );
//rabbitmq 3.7以后就别这么写了。直接new WebSocketStompClient(client)就行
WebSocketClient transport = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(transport);
//StompSessionHandlerAdapter默认的payload类型是String, 因此MessageConverter必须是StringMessageConverter
stompClient.setMessageConverter(new StringMessageConverter()); final CustomStompSessionHandler sessionHandler =
new CustomStompSessionHandler(dest, toSend); WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
headers.setSecWebSocketProtocol("13"); //连接用户名/密码也是必须的,否则连不上
StompHeaders sHeaders = new StompHeaders();
sHeaders.add("login", this.login);
sHeaders.add("passcode", this.passCode); //开始连接,回调连接上后发送stomp消息
stompClient.connect(url, headers, sHeaders, sessionHandler); //要同步得到发送结果的话,用CountDownLatch来做或者connect结果的future对象做get
} }

然后编写回调handler类。

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; /**
* 自定义stomp session 回调handler
* @author Selwyn
* @version $Id: CustomStompSessionHandler.java, v 0.1 9/7/2018 3:43 PM Selwyn Exp $
*/
@Slf4j
public class CustomStompSessionHandler extends StompSessionHandlerAdapter { /**
* 要发送的对象,将会json化传输出去
*/
private Object toSend; /**
* 目的地,一般是topic地址
*/
private String dest; public CustomStompSessionHandler(String dest, Object toSend) {
this.toSend = toSend;
this.dest = dest;
} @Override
public void handleFrame(StompHeaders headers, Object payload) {
super.handleFrame(headers, payload);
} @Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
super.afterConnected(session, connectedHeaders);
String msg = JSON.toJSONString(toSend);
try{
session.send(dest, msg);
}catch(Exception e)
{
log.error("failed to send stomp msg({}) to destination {}", msg, dest);
}finally {
//做完了关闭呗
session.disconnect();
}
} @Override
public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
super.handleException(session, command, headers, payload, exception);
log.error("stomp error: {}", exception);
} @Override
public void handleTransportError(StompSession session, Throwable exception) {
super.handleTransportError(session, exception);
log.error("stomp transport error: {}", exception);
} public void setToSend(Object toSend) {
this.toSend = toSend;
} public void setDest(String dest) {
this.dest = dest;
}
}

再自己写个controller或者写个单元测试方法,这里就不给出代码了,撸完后启动服务,就可以测试消息推送了,实践证明,真香!

结尾:

其实整个过程还没完,需要考虑到连接中断等情况,客户端和服务后台都需要做好重连机制。通过sockjs这种方式连接是没有心跳机制的,这个比activemq带的stomp插件要low。个人建议,如果能用spring boot的话尽量用那种方式去实现stomp消息推送。

  

spring+rabbitmq+stomp搭建websocket消息推送(非spring boot方式)的更多相关文章

  1. 搭建websocket消息推送服务,必须要考虑的几个问题

    近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对websocket的要求也越来越高.从早期对websocket的应 ...

  2. node.js Websocket消息推送---GoEasy

    Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送 速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送 支持websocket ...

  3. C(++) Websocket消息推送---GoEasy

    Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送 速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送 支持websocket ...

  4. 【WebSocket】WebSocket消息推送

    准备使用WebSocket实现Java与Vue或者安卓间的实时通信,实现私密聊天.群聊.查询下资料备用. WebSocket客户端 websocket允许通过JavaScript建立与远程服务器的连接 ...

  5. spring boot下WebSocket消息推送(转)

    原文地址:https://www.cnblogs.com/betterboyz/p/8669879.html WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.W ...

  6. spring boot下WebSocket消息推送

    WebSocket协议 WebSocket是一种在单个TCP连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范.WebSo ...

  7. websocket消息推送实现

    一.服务层 package com.demo.websocket; import java.io.IOException; import java.util.Iterator; import java ...

  8. WebSocket消息推送

    WebSocket协议是基于TCP的一种新的网络协议,应用层,是TCP/IP协议的子集. 它实现了浏览器与服务器全双工(full-duplex)通信,客户端和服务器都可以向对方主动发送和接收数据.在J ...

  9. swoole WebSocket 消息推送

    server.php <?php //连接本地的 Redis 服务 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $r ...

随机推荐

  1. Canvas,Matrix的变换顺序

    Canvas的几何变换是倒序的,Matrix是正序. 比如先平移在旋转: canvas.rotate(); canvas.translate(); //translate先执行,rotate后执行 M ...

  2. spring boot jar 部署linux服务器

    用命令启动spring boot 项目,一旦终端命令窗口关闭,项目也就关闭了,所以我们采用脚本的方式来运行jar 正常命令 java -jar xxx.jar 脚本启动,vim 创建 start.sh ...

  3. Method and system for implementing mandatory file access control in native discretionary access control environments

    A method is provided for implementing a mandatory access control model in operating systems which na ...

  4. 为什么唱iOS 6.0选择Mantle

    近来的mt=8" target="_blank" rel="external">iOS的6.0版本号已经成功上线了. 18人月的投入,2500个 ...

  5. 实现在 .net 中使用 HttpClient 下载文件时显示进度

    在 .net framework 中,要实现下载文件并显示进度的话,最简单的做法是使用 WebClient 类.订阅 DownloadProgressChanged 事件就行了. 但是很可惜,WebC ...

  6. Java 中override、overload、overwrite区别,以及与多态的关系【转】

    因为早期的翻译导致了override和overwrite的解释及理解混乱,需要重新梳理这几个词及相关内容. 转自:http://blog.csdn.net/lzhang007/article/deta ...

  7. MFC 窗口分割与通信

    一.关于CSplitterWnd类我们在使用CuteFtp或者NetAnt等工具的时候,一般都会被其复杂的界面所吸引,在这些界面中窗口被分割为若干的区域,真正做到了窗口的任意分割. 那么我们自己如何创 ...

  8. &lt;PC&gt;HP网络共享并创建一个热点问题

    郁闷了一年多 你不能使用本地连接的开放热点 网上说的网卡驱动程序,系统设置等.,我们解决不了 原本BIOS节能设置错误 导致在连续主动对自己的有线无线功能被禁用 该LAN\WLAN  Switchin ...

  9. debian8 root无法远程登录解决办法

    改一下root 密码,应该就能本地登录了. 改/etc/ssh/sshd.conf,然后重启ssh就能远程登录了:PermitRootLogin yesPermitEmptyPasswords no

  10. MIME映射(程序映射)

    MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器 ...