一、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. 屏蔽响应事件继续向父视图传递的category

    屏蔽响应事件继续向父视图传递的category 这篇教程是上一篇教程的升级版,将复杂的代码封装成了category,更便于使用:) 效果: 源码: UIGestureRecognizer+EnvetI ...

  2. UNIX高级环境编程(6)标准IO函数库 - 流的概念和操作

    标准IO函数库隐藏了buffer大小和分配的细节,使得我们可以不用关心预分配的内存大小是否正确的问题. 虽然这使得这个函数库很容易用,但是如果我们对函数的原理不熟悉的话,也容易遇到很多问题.   1 ...

  3. 剑指offer 10矩形覆盖

    我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法 java版本: public class Solution { publ ...

  4. 如何创建一个Quartz.NET的工作,需要注射autofac

    问题: 使用 Quartz.Net 做定时任务时,实现IJob对象的服务,Autofac不会自动注入,使用构造函数会直接出现异常,无法执行Execute方法. 解决方式 方法一: 使用 Autofac ...

  5. 微信小程序初始化 operateWXData:fail invalid scope

    初学者开发微信小程序,可以使用云开发来进行微信小程序的开发. 第一次使用开发工具遇到的问题 解决方案:1.找到云开发 2.点击开通,选择合适自己的开发环境: 3.完成后,返回开发工具界面点击项目第一个 ...

  6. super深究

    super的入门使用: 在类的继承中,如果定义某个方法,该方法会覆盖父类的同名方法,但有时候我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可以通过使用super来实现.比如: cla ...

  7. JavaScript创建对象的6种方式

    JavaScript创建对象简单的说,无非就是使用内置对象(Object)或各种自定义对象,当然还可以用JSON,但写法有很多种,也能混合使用. 1.对象字面量的方式 person = {name : ...

  8. JVM虚拟机21: 1.8中废弃永久代(PermGen)迎来元空间(Metaspace)

    1.JDK8永久代的废弃 JDK8 永久代变化如下图: 1.新生代:Eden+From Survivor+To Survivor 2.老年代:OldGen 3.永久代(方法区的实现) : PermGe ...

  9. 【转】Android应用如何跳转到应用市场详情页面

    Android应用开发过程中,可能会有需求,比如:推广时跳转到应用市场下载应用,跳转到应用市场给自己的应用打分,跳转到应用市场更新自己的应用.那如何跳转到应用市场呢? 可能跳转的方法大家都是知道的,方 ...

  10. weblogic之CVE-2018-3191漏洞分析

    weblogic之CVE-2018-3191漏洞分析 理解这个漏洞首先需要看这篇文章:https://www.cnblogs.com/afanti/p/10193169.html 引用廖新喜说的,说白 ...