WebSocket的那些事(3-STOMP实操篇)

这篇具有很好参考价值的文章主要介绍了WebSocket的那些事(3-STOMP实操篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、序言

上节中我们在 WebSocket的那些事(2-实操篇)中简单介绍了Spring中对于WebSocket的封装,并实现一个简单的服务端,这节我们将会结合STOMP子协议实现WebSocket通信。


二、STOMP详解

1、STOMP简单介绍

WebSocket协议定义了两种消息类型(文本类型和二进制类型),但是消息内容却是未定义的,下面我们介绍一下STOMP协议。

STOMP (Simple Text Oriented Messaging Protocol) 起源于脚本语言,比如Ruby、Python和Perl,用于连接企业消息代理,它可以用于任何可靠的双向网络协议中,如TCP和WebSocket。尽管STOMP是一个面向文本的协议,但消息负载可以是文本或者二进制。

STOMP基于WebSocket在客户端和服务端之间定义了一种机制,协商通过子协议(更高级的消息协议)来定义可以发送何种消息,每条消息的内容是什么,等等。

2、STOMP协议内容

STOMP是一个基于帧的协议,帧的结构如下:

COMMAND
header1:value1
header2:value2

Body

客户端可以用SEND或者SUBSCRIBE命令去发送和订阅消息,destination头部用来描述消息发送到哪里以及谁应该接收消息,下面的消息结构是客户端订阅股票行情的例子,如下:

SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*

下面的消息结构是客户端发送交易请求的例子,如下:

SEND
destination:/queue/trade
content-type:application/json
content-length:44

{"action":"BUY","ticker":"MMM","shares",44}

STOMP服务端可以使用MESSAGE命令广播消息给所有的订阅者,下面的例子为广播股票行情消息给所有消息订阅者。

MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM

{"ticker":"MMM","price":129.45}

3、使用STOMP的好处

在Spring中使用STOMP与原生WebSockets相比提供了更加丰富的编程模型,下面是使用STOMP的优点:

  • 不需要发明自定义消息协议和消息格式。
  • 在Spring中,STOMP客户端,包括Java客户端都可用。
  • 可使用其它消息代理管理消息订阅和广播,如RabbitMQActiveMQ等支持STOMP协议的中间件。
  • 应用逻辑处理入口可以像Spring MVC一样统一在@Controller实例内,同时消息可以基于STOMP头部消息进行路由,而不是直接用WebSocketHandler处理原生WebSocket消息。
  • 可以基于STOMP目的地和消息类型使用Spring Security对消息进行安全传输。

三、代码示例

1、Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

备注:这里我就简单用Thymeleaf作模板引擎,为了方便调试在application.yml中将spring.thymeleaf.cache设为false来禁用模板缓存。

2、开启WebSocket消息代理

@Configuration
@EnableWebSocketMessageBroker
public class WebsocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/websocket") // WebSocket握手端口
			.addInterceptors(new HttpSessionHandshakeInterceptor())
			.setAllowedOriginPatterns("*") // 设置跨域
			.withSockJS(); // 开启SockJS回退机制
	}

	@Override
	public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
		// 这里我们设置入站消息最大为8K
		registry.setMessageSizeLimit(8 * 1024);
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.setApplicationDestinationPrefixes("/app") // 发送到服务端目的地前缀
			.enableSimpleBroker("/topic");// 开启简单消息代理,指定消息订阅前缀
	}

}

备注:

  1. 关于SockJS的介绍请参考上篇文章 WebSocket的那些事(1-概念篇)最后部分。
  2. setApplicationDestinationPrefixes的意思是以目的地以/app开头的消息将会被路由到Controller实例中的方法进行处理。
  3. enableSimpleBroker将会启用一个内置的内存消息代理,用于订阅、广播和路由消息。

3、控制器

@Slf4j
@Controller
public class GreetingController {

	@GetMapping("/page/greeting")
	public ModelAndView turnToGreetingPage() {
		return new ModelAndView("/greeting");
	}

	@MessageMapping("/greeting")
	public String sayGreeting(String name) {
		log.info("Message received: {}", name);
		return "Hello, " + name;
	}
}

4、前端页面greeting.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>greeting</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <style>
        #mainWrapper {
            width: 600px;
            margin: auto;
        }
    </style>
</head>
<body>
<div id="mainWrapper">
    <div id="msgWrapper">
        <p style="vertical-align: top">发送的消息:</p>
        <textarea id="msgSent" style="width: 400px;height: 100px"></textarea>
        <p style="vertical-align: top">收到的消息:</p>
        <textarea id="msgReceived" style="width: 400px;height: 100px"></textarea>
    </div>
    <div style="margin-top: 5px;">
        <button onclick="connect()">连接</button>
        <button onclick="sendMessage()">发送消息</button>
        <button onclick="disconnect()">断开连接</button>
    </div>
</div>
<script type="text/javascript">
    $(() => {
        $('#msgSent').val('');
        $("#msgReceived").val('');
    });

    let stompClient = null;

    // 连接服务器
    const connect = () => {
        const ws = new SockJS('http://localhost:8080/websocket');
        stompClient = Stomp.over(ws);
        stompClient.connect({}, () => {
            $("#msgReceived").val('Connected to websocket server!');
            stompClient.subscribe('/topic/greeting', function (message) {
                    console.log(`Received message: ${message.body}`);
                    $("#msgReceived").val(message.body);
                }
            );
        });
    }

    // 断连
    const disconnect = () => {
        stompClient.disconnect(() => {
            $("#msgReceived").val('Disconnected from WebSocket server');
        });
    }

    // 发送消息,这里直接发的是文本
    const sendMessage = () => {
        stompClient.send('/app/greeting', {}, $('#msgSent').val());
    }
</script>
</body>
</html>

备注:

  1. greeting.htmlThymeleaf模板页面,文件直接放在类路径templates目录下即可.
  2. 这里我们选用了SockJS去连接服务端,为什么使用SockJS请参考 WebSocket的那些事(1-概念篇),同时注意协议名称是http而不是ws

四、测试

浏览器输入http://localhost:8080/page/greeting即可跳转到我们的页面,如下:
WebSocket的那些事(3-STOMP实操篇)

1、连接服务端

点击连接按钮后,我们发现已经与服务端成功建立连接。我们可以观察到客户端发送了两条命令,一条是Connect建立连接命令,另一条是连接建立成功后的SUBSCRIBE命令,用来订阅目的地为/topic/greeting的消息。

WebSocket的那些事(3-STOMP实操篇)

2、发送消息

点击发送按钮发送消息,可以看到服务端也返回了Hello, Nick的回复消息。
WebSocket的那些事(3-STOMP实操篇)

备注:我们可以看到客户端发送了一条SEND命令,目的地为/app/greeting,内容长度为4个字节。同时服务端回复了一条MESSAGE命令,这条命令的意思是广播消息给所有订阅/topic/greeting的客户端。


五、STOMP消息传播流程

一旦STOMP端点暴露,Spring应用对于连接的客户端就变成了STOMP代理,下面我们简单介绍一下服务端消息传播流程。
WebSocket的那些事(3-STOMP实操篇)
上面的图展示了三种消息渠道:

  • clientInboundChannel: 客户端消息入站通道,用来传递WebSocket客户端接收的消息。
  • clientOutboundChannel: 客户端消息出站通道,用来发送服务端消息给WebSocket客户端。
  • brokerChannel: 消息代理通道,用来在服务层传递消息给消息代理。

目的地以/app开头的消息会通过clientInboundChannel路由到MessageHandler消息处理器进行处理,然后再将消息通过brokerChannel发送到SimpleBroker中。

目的地以/topic开头的消息会通过clientInboundChannel直接路由到SimpleBroker中进行处理。

上图中的SimpleBroker实际上是Spring基于内存的内置消息代理,实际上Spring也支持集成其它支持STOMP协议的MQ,如ActiveMQ、RabbitMQ等,集成外部消息代理的消息传播流程图如下:

WebSocket的那些事(3-STOMP实操篇)
从上图中,我们可以看到StompBrokerRelay会和外部消息代理进行通信,通过enableStompBrokerRelay即可以集成外部消息代理,关于集成外部消息代理的例子和细节我们在后面的章节在讨论。


六、结语

这节我们简单介绍了STOMP协议、Spring中对WebSocketSTOMP支持以及具体的代码集成示例。

下节我们将会具体介绍@Controller控制器中相关消息注解的使用示例和细节,如@MessageMapping@SubscribeMapping@MessageExceptionHandler@SendTo@SendToUser等。

WebSocket的那些事(3-STOMP实操篇)文章来源地址https://www.toymoban.com/news/detail-464738.html

到了这里,关于WebSocket的那些事(3-STOMP实操篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)

    上节我们在 WebSocket的那些事(4-Spring中的STOMP支持详解) 中详细说明了通过 Spring内置消息代理 结合 STOMP 子协议进行Websocket通信,以及相关注解的使用及原理。 但是Spring内置消息代理会有一些限制,比如只支持STOMP协议的一部分命令,像 acks 、 receipts 命令都是不支持的,还有

    2024年02月09日
    浏览(28)
  • Linux 实操篇-实用指令

    基本介绍 运行级别说明: 0 :关机 1 :单用户【找回丢失密码】 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用运行级别是3 和5 ,也可以指定默认运行级别, ​ 命令 :init [0123456] 在centos7 以前, /etc/inittab 文

    2024年02月08日
    浏览(31)
  • Linux(实操篇三)

    1.7 搜索查找类 1.7.1 find查找文件或目录 find 指令将 从指定目录向下递归地遍历其各个子目录 ,将满足条件的文件显示在终端。 基本语法 find [搜索范围] [选项] 选项说明 -name查询方式 按照指定的文件名查找模式查找文件 -user用户名 查找属于指定用户名所有文件 -size文件大小

    2024年02月10日
    浏览(27)
  • Linux—实操篇:用户管理

    Linux系统是一个多用户多任务的操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个 账号,然后以这个账号的身份进入系统。 基本语法: useradd 用户名 细节说明: 1、当创建用户成功后,会自动创建一个和用户同名的家目录 2、通过 useradd -d 指定目

    2024年02月12日
    浏览(45)
  • Linux(实操篇一)

    Shell 可以看作是一个命令解释器,为我们提供了交互式的文本控制台界面。我们可以 通过终端控制台来输入命令,由 shell 进行解释并最终交给内核执行。 1.1 帮助命令 1.1.1 man获得帮助信息 基本语法 man [命令或配置文件] 功能描述:获得帮助信息 显示说明 NAME:命令的名称和

    2024年02月11日
    浏览(28)
  • Linux(实操篇二)

    1.3 时间日期类 基本语法 date [OPTION]… [+FORMAT] 选项说明 -d时间字符串 显示指定的“时间字符串”表示的时间,而非当前时间 -s日期时间 设置系统日期时间 参数说明 +日期时间格式 指定显示时使用的日期时间格式 1.3.1 date显示当前时间 基本语法 (1)date 功能描述:显示当前时

    2024年02月11日
    浏览(33)
  • Linux 实操篇--定时任务调度

    crontab 进行定时任务的设置 概述 任务调度:是指系统在某个时间执行的特定的命令或程序。 任务调度分类:1.系统工作:有些重要的工作必须周而复始地执行。如病毒扫描等 个别用户工作:个别用户可能希望执行某些程序,比如对mysql 数据库的备份。 示意图 基本语法 cron

    2024年02月07日
    浏览(42)
  • 9 Linux实操篇-实用指令

    学习视频来自于B站【小白入门 通俗易懂】2021韩顺平 一周学会Linux。 可能会用到的资料有如下所示,下载链接见文末: 《鸟哥的Linux私房菜 基础学习篇 第四版》 1 《鸟哥的Linux私房菜 服务器架设篇 第三版》 2 《韩顺平_2021图解Linux全面升级》 3 本章将介绍在Linux会大量使用的

    2024年02月15日
    浏览(31)
  • flowable工作流--实操篇

    本文通过申请发工资的业务场景来介绍使用工作流的全流程,包括画流程图,设置属性,以及代码编写 使用工作流大致分为四步 第一步:根据自己的业务画好流程图 第二步:设置流程图的属性和变量,保存模型 第三步:部署画好的流程图(发布) 第四步:根据业务和流程图写一些服务和

    2024年02月11日
    浏览(43)
  • 【linux】linux实操篇之任务调度

    我们常用linux做一些定时任务,最常见的就是在服务器领域,我们常常做一些定时任务来定时执行一些脚本,那么接下来我们就来看看linux中的任务调度相关知识以及一些案例吧! 用 crontab 进行定时任务的设置 概述 任务调度:是指系统在某个时间执行的特定的命令或程序。

    2024年02月02日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包