一、WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

  WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

  二、STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。

  三、首先,我们先理解一下为什么需要STOMP。

  1)常规的websocket连接和普通的TCP基本上没有什么差别的。

  2)那我们如果像http一样加入一些响应和请求层。

  3)所以STOMP在websocket上提供了一中基于帧线路格式(frame-based wire format)。

  4)简单一点,就是在我们的websocket(TCP)上面加了一层协议,使双方遵循这种协议来发送消息。

  四、STOMP

  1)Frame

  

  例如:

  

  command:CONNECT

  其他部分都是headers的一部分。

  2)command类别

    CONNECT

    SEND

    SUBSCRIBE

    UNSUBSCRIBE

    BEGIN

    COMMIT

    ABORT

    ACK

    NACK

    DISCONNECT

  3)客户端常用连接方式

  a、ws  

  var url = "ws://localhost:8080/websocket";
var client = Stomp.client(url);

  b、sockJs

  <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
// use SockJS implementation instead of the browser's native implementation
var ws = new SockJS(url);
var client = Stomp.over(ws);
[...]
</script>

  说明:使用ws协议需要浏览器的支持,但是一些老版本的浏览器不一定支持。Stomp.over(ws)的凡是就是用来定义服务websocket的协议。

  4)服务端的实现过程

  

  a、服务端:/app,这里访问服务端,前缀通过设定的方式访问。

  b、用户:/user,这里针对的是用户消息的传递,针对于当前用户进行传递。

  c、其他消息:/topic、/queue,这两种方式。都是定义出来用于订阅。并且消息只能从这里通过并处理

  五、springboot的简单例子

  1)目录结构

  

  2)依赖包(pom.xml)

    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>

  3)websocket配置(WebSocketConfiguration、SecurityConfiguration

/**
* webSocket配置
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer { /**
* 注册stomp端点,主要是起到连接作用
* @param stompEndpointRegistry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry
.addEndpoint("/webSocket") //端点名称
//.setHandshakeHandler() 握手处理,主要是连接的时候认证获取其他数据验证等
//.addInterceptors() 拦截处理,和http拦截类似
.setAllowedOrigins("*") //跨域
.withSockJS(); //使用sockJS } /**
* 注册相关服务
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//这里使用的是内存模式,生产环境可以使用rabbitmq或者其他mq。
//这里注册两个,主要是目的是将广播和队列分开。
//registry.enableStompBrokerRelay().setRelayHost().setRelayPort() 其他方式
registry.enableSimpleBroker("/topic", "/queue");
//客户端名称前缀
registry.setApplicationDestinationPrefixes("/app");
//用户名称前
registry.setUserDestinationPrefix("/user");
}
}

  认证配置:

/**
* 配置基本登录
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ /**
* 加密方式
*/
@Autowired
private BCryptPasswordEncoder passwordEncoder; /**
* 所有请求过滤,包含webSocket
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
} /**
* 加入两个用户测试不同用的接受情况
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder.encode("admin")).roles("ADMIN")
.and()
.withUser("user").password(passwordEncoder.encode("user")).roles("USER");
} @Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}

  4)服务端

/**
* 消息接收处理
*/
@RestController
public class MessageResource { //spring提供的推送方式
@Autowired
private SimpMessagingTemplate messagingTemplate; /**
* 广播模式
* @param requestMsg
* @return
*/
@MessageMapping("/broadcast")
@SendTo("/topic/broadcast")
public String broadcast(RequestMsg requestMsg) {
//这里是有return,如果不写@SendTo默认和/topic/broadcast一样
return "server:" + requestMsg.getBody().toString();
} /**
* 订阅模式,只是在订阅的时候触发,可以理解为:访问——>返回数据
* @param id
* @return
*/
@SubscribeMapping("/subscribe/{id}")
public String subscribe(@DestinationVariable Long id) {
return "success";
} /**
* 用户模式
* @param requestMsg
* @param principal
*/
@MessageMapping("/one")
//@SendToUser("/queue/one") 如果存在return,可以使用这种方式
public void one(RequestMsg requestMsg, Principal principal) {
//这里使用的是spring的security的认证体系,所以直接使用Principal获取用户信息即可。
//注意为什么使用queue,主要目的是为了区分广播和队列的方式。实际采用topic,也没有关系。但是为了好理解
messagingTemplate.convertAndSendToUser(principal.getName(), "/queue/one", requestMsg.getBody());
}
}

  客户端(JavaScript):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webSocket</title>
<script src="js/jquery.js"></script>
<script src="js/sockjs.min.js"></script>
<script src="js/stomp.js"></script>
</head>
<body>
<div>
<button id="connect">连接</button>
<button id="disconnect" disabled="disabled">断开</button>
</div>
<div>
<h3>广播形式</h3>
<button id="broadcastButton">发送</button><input id="broadcastText" type="text">
<label>广播消息:</label><input id="broadcastMsg" type="text" disabled="disabled">
</div>
<div>
<h3>订阅形式</h3>
<label>订阅消息:</label><input id="subscribeMsg" type="text" disabled="disabled">
</div>
<div>
<h3>角色形式</h3>
<button id="userButton">发送</button><input id="userText" type="text">
<label>用户消息:</label><input id="userMsg" type="text" disabled="disabled">
</div>
<div>
<h3>无APP</h3>
<button id="appButton">发送</button><input id="appText" type="text">
<label>前端消息:</label><input id="appMsg" type="text" disabled="disabled">
</div>
</body>
<script>
var stomp = null;
$("#connect").click(function () {
var url = "http://localhost:8080/webSocket"
var socket = new SockJS(url);
stomp = Stomp.over(socket);
//连接
stomp.connect({}, function (frame) {
//订阅广播
stomp.subscribe("/topic/broadcast", function (res) {
$("#broadcastMsg").val(res.body);
});
//订阅,一般只有订阅的时候在返回
stomp.subscribe("/app/subscribe/1", function (res) {
$("#subscribeMsg").val(res.body);
});
//用户模式
stomp.subscribe("/user/queue/one", function (res) {
$("#userMsg").val(res.body);
});
//无APP
stomp.subscribe("/topic/app", function (res) {
$("#appMsg").val(res.body);
});
setConnect(true);
});
}); $("#disconnect").click(function () {
if (stomp != null) {
stomp.disconnect();
}
setConnect(false);
});
//设置按钮
function setConnect(connectStatus) {
$("#connect").attr("disabled", connectStatus);
$("#disconnect").attr("disabled", !connectStatus);
} //发送广播消息
$("#broadcastButton").click(function () {
stomp.send("/app/broadcast", {}, JSON.stringify({"body":$("#broadcastText").val()}))
}); //发送用户消息
$("#userButton").click(function () {
stomp.send("/app/one", {}, JSON.stringify({"body":$("#userText").val()}))
}); //发送web消息
$("#appButton").click(function () {
stomp.send("/topic/app", {}, JSON.stringify({"body":$("#appText").val()}))
});
</script>
</html>

  5)普通测试

  角色测试:

  六、相关资料

  http://jmesnil.net/stomp-websocket/doc/

  七、源码:https://github.com/lilin409546297/springboot-websocket

springboot之websocket,STOMP协议的更多相关文章

  1. 【Java分享客栈】SpringBoot整合WebSocket+Stomp搭建群聊项目

    前言 前两周经常有大学生小伙伴私信给我,问我可否有偿提供毕设帮助,我说暂时没有这个打算,因为工作实在太忙,现阶段无法投入到这样的领域内,其中有两个小伙伴又问到我websocket该怎么使用,想给自己的 ...

  2. springboot websocket集群(stomp协议)连接时候传递参数

    最近在公司项目中接到个需求.就是后台跟前端浏览器要保持长连接,后台主动往前台推数据. 网上查了下,websocket stomp协议处理这个很简单.尤其是跟springboot 集成. 但是由于开始是 ...

  3. springboot+websocket+sockjs进行消息推送【基于STOMP协议】

    springboot+websocket+sockjs进行消息推送[基于STOMP协议] WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就 ...

  4. springBoot -webSocket 基于STOMP协议交互

    浅谈WebSocket WebSocket是在HTML5基础上单个TCP连接上进行全双工通讯的协议,只要浏览器和服务器进行一次握手,就可以建立一条快速通道,两者就可以实现数据互传了.说白了,就是打破了 ...

  5. SpringBoot WebSocket STOMP 广播配置

    目录 1. 前言 2. STOMP协议 3. SpringBoot WebSocket集成 3.1 导入websocket包 3.2 配置WebSocket 3.3 对外暴露接口 4. 前端对接测试 ...

  6. websocket的子协议stomp协议

    stomp协议Spring实现 服务器注册EndPoint 用来与客户端建立websocket连接 websocket连接的建立应该与客户端与服务器之间的通道无关 jdk中 javax下的websoc ...

  7. Spring Boot实现STOMP协议的WebSocket

    关注公众号:锅外的大佬 每日推送国外优秀的技术翻译文章,励志帮助国内的开发者更好地成长! WebSocket协议是应用程序处理实时消息的方法之一.最常见的替代方案是长轮询(long polling)和 ...

  8. spring-boot支持websocket

    spring-boot本身对websocket提供了很好的支持,可以直接原生支持sockjs和stomp协议.百度搜了一些中文文档,虽然也能实现websocket,但是并没有直接使用spring-bo ...

  9. SpringBoot 整合 WebSocket

    SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...

随机推荐

  1. 转:HTTP Status 404(The requested resource is not available)的几种解决方法

    原文地址 原因:servlet没有配置正确 ,查看web.xml确认正确,以及自己的请求路径正确 在IE中提示“404”错误有以下三种情况 1.未部署Web应用 2.URL输入错误 排错方法: 首先, ...

  2. 生成器(generator),迭代器(yield)

    g=(i for i in range(10)) #小括号表示生成一个迭代生成器.[]是列表生成器 g.__next__() yield将一个函数变成生成器 import time def f(): ...

  3. mvc 下json超过限制,上传excel大小限制

    json超过限制 解决方案1:config中添加节点  控制序列化长度 <webServices> <jsonSerialization maxJsonLength="10 ...

  4. CSS学习摘要-布局

    注:全文摘自MDN-介绍CSS布局 CSS页面布局技术允许我们拾取网页中的元素,并且控制它们相对正常布局流.周边元素.父容器或者主视口/窗口的位置.在这个模块中将涉及更多关于页面布局技术的细节: 浮动 ...

  5. Hadoop HBase概念学习系列之HBase里的长表VS宽表VS窄表(十五)

    有时候啊,HBase表的设计方案通常,还会考虑如下一些因素,当然,这只是考虑范围里的部分呢. 更多的行还是更多的版本?后者使用了HBase自带的功能.但是需要在列簇中定义最大版本数,这样做可能有风险. ...

  6. [微信小程序直播平台开发]___(三)Nginx-rtmp事件回调

    1.一个可以忽略的前言 发起直播后可以在Nginx的自带的页面上查看到统计,那怎么知道发起了直播或者关闭了直播呢?我想到了这个统计页,于是查看一下里面的内容看看如何获取到的数据, 找到后发现是个xsl ...

  7. Php发送post请求方法

    因为自己时常用到 所以还是发布一下吧 /** * 发送post请求 * @param string $url 请求地址 * @param array $post_data post键值对数据 * @r ...

  8. CentOS 7下启动、关闭、重启、查看MySQL服务

    1.启动命令 [root@xufeng Desktop]# service mysqld startRedirecting to /bin/systemctl start mysqld.service ...

  9. Azkaban时区问题导致调度差1天

    设置了Azkaban调度是每日凌晨一次,如下: 但是调度历史上显示最近一次调度时间是 初步怀疑是因为时区问题导致,查看服务器时区如下 cat /etc/timezone 为Asia/Shanghai. ...

  10. php基础学习-sdy

    1.php语言结构和函数 exit()和die() exit()相当于把下面的代码都注释了 die()终止脚本 两个差不多 函数有很多种 (1)语言结构 (2)自定义函数 (3)内置函数 functi ...