当前位置: 首页 > 编程笔记 >

SpringWebsocket +Stomp+SockJS实现消息订阅和推送详解

邢寒
2023-05-05

一、STOMP协议介绍

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

STOMP协议的前身是TTMP协议(一个简单的基于文本的协议),专为消息中间件设计。

STOMP是一个非常简单和容易实现的协议,其设计灵感源自于HTTP的简单性。尽管STOMP协议在服务器端的实现可能有一定的难度,但客户端的实现却很容易。例如,可以使用Telnet登录到任何的STOMP代理,并与STOMP代理进行交互。

二、SockJS介绍

SockJS 是一个浏览器上运行的 JavaScript 库,如果浏览器不支持 WebSocket,该库可以模拟对 WebSocket 的支持,实现浏览器和 Web 服务器之间低延迟、全双工、跨域的通讯通道。

三、websocket 是什么?

是一种网络通信协议,很多高级功能都需要它

四、为什么要使用websocket?

已经有了HTTP协议 为撒还需要使用WebSocket 嘞?

HTTP 是客户端请求服务端响应数据,但是我们如果想服务端给客户端发送消息嘞?

于是乎就有了这种协议,客户端,服务端可以双向发送消息最典型的就是聊天系统

五、为什么需要stomp?

常规的websocket连接和普通的TCP基本上没区别

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

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

 

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

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

其他消息:/topic、/queue,这两种方式。都是定义出来用于订阅服务端  

需求

APP用户发起申请操作,需要让后台管理系统部分人员感知(审核提醒 消息提示)。

主要侧重介绍下 服务器主动推送,由服务端来触发。

WebSocket 主要能实现的场景

1、网页聊天室

2、服务器消息实时通知

 

来吧,展示~

1.导入pom依赖

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

2.websocket配置 - WebSocketConfig

/**
 * 	通过EnableWebSocketMessageBroker 开启使用STOMP协议来传输基于代理(message broker)的消息,此时浏览器支持使用@MessageMapping 就像支持@RequestMapping一样。
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    /**
    * 基于STOMP协议的WebSocket
    * endPoint 注册协议节点,并映射指定的URl
    *
    * @param registry
    */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册一个websocket端点,客户端将使用它连接到我们的websocket服务器。
        registry.addEndpoint("/socket").setAllowedOrigins("*").withSockJS();
    }
    /**
    * 注册相关服务
    * 配置消息代理(message broker)
    *
    * @param registry
    */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //定义了服务端接收地址的前缀,也即客户端给服务端发消息的地址前缀
        registry.setApplicationDestinationPrefixes("/yifan");
        //定义了一个(或多个)客户端订阅地址的前缀信息,也就是客户端接收服务端发送消息的前缀信息
        registry.enableSimpleBroker("/topic", "/user");
        // 点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
        registry.setUserDestinationPrefix("/user/");
    }
}

介绍以上几个相关的注解和方法:

  • @EnableWebSocketMessageBroker:开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样。

  • AbstractWebSocketMessageBrokerConfigurer:继承WebSocket消息代理的类,配置相关信息。

  • registry.addEndpoint("/endpointOyzc").setAllowedOrigins("*").withSockJS(); 添加一个访问端点“/endpointGym”,客户端打开双通道时需要的url,允许所有的域名跨域访问,指定使用SockJS协议。

  • registry.enableSimpleBroker("/topic","/user"); 配置一个/topic广播消息代理和“/user”一对一消息代理

  • registry.setUserDestinationPrefix("/user");点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/

3.产生一个消息

@Controller
//@RequestMapping("/yifan/{user}")
@RequestMapping("yifan")
public class ChatController {
    @Autowired
    private SimpMessagingTemplate template;
    /* 接收消息     @SendToUser 谁发送的返回给谁  */
    @MessageMapping("/chatTo")
    public void apply(SocketMessage message){
        /* 发送给个人*/
        // template.convertAndSendToUser(userDO.toString(), "/topic/notifications", "新消息:" + notify.getTitle());
        /* 发送给全部*/
        template.convertAndSend("/topic/getResponse", new Response("客户xxx发起申请,请及时处理!" ));
    }
    
    @MessageMapping("/chatTo") // 浏览器发送请求通过@messageMapping 映射/welcome 这个地址。
	@SendTo("/topic/getResponse") // 服务器端有消息时,会订阅@SendTo 中的路径的浏览器发送消息。
	public Response say(Message message) throws Exception {
		Thread.sleep(1000);
		return new Response("Welcome, " + message.getName() + "!");
	}
}

4.客户端 网页

需要准备

  • jquery.min.js https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js

  • sockjs.min.js sockjs

  • stomp.js stomp

<html>
    // 消息框
    ....
    // 提示音控件
    <audio ref="msgTipAudio" controls="controls" id="music" hidden>
        <source src="/img/audio/tip.mp3" type="audio/mpeg"/>
        Your browser does not support the audio element.
    </audio>
</html>
<script type="text/javascript">
    var stompClient = null;
    $(function () {
        connect();
    });
    function connect() {
        //连接SockJS的endpoint名称为"endpointOyzc"
        var sock = new SockJS("/endpointChat");
        var stomp = Stomp.over(sock);
        stomp.connect('guest', 'guest', function(frame) {
            /**
 订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致,

             *  这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。

             *  */
            stomp.subscribe("/user/queue/notifications", handleNotification);
            stomp.subscribe('/topic/getResponse', function (response) { //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。
                toastr.options = {
                    "closeButton": true,
                    "debug": false,
                    "progressBar": true,
                    "positionClass": "toast-bottom-right",
                    "onclick": null,
                    "showDuration": "400",
                    "hideDuration": "1000",
                    "timeOut": "7000",
                    "extendedTimeOut": "1000",
                    "showEasing": "swing",
                    "hideEasing": "linear",
                    "showMethod": "fadeIn",
                    "hideMethod": "fadeOut"
                }
                toastr.info(JSON.parse(response.body).responseMessage);
                // 消息提示音JS
                var audio = document.getElementById('music');
                audio.play();// 播放
            });
        });
        function handleNotification(message) {
            wrapper.notify();
            toastr.info(message.body);
        }
    }
</script>

 

 类似资料:
  • 我正在尝试使用Springframework SimpMessageTemplate(默认Stomp实现)来流式传输时间序列数据,以将消息广播到SockJS客户端订阅的主题。但是,这些消息是按顺序接收的。服务器是单线程的,消息按时间戳升序发送。客户端以某种方式接收到了顺序错误的消息。 我使用的是stompjs和springframework的最新版本(4.1.6版本)。

  • 我正在开发一个利用websockets功能的Spring应用程序。为了使它更健壮,我使用了STOMP/SimpleBrokerMessageHandler,如文档中所述。一切进展顺利,我已经能够非常快速地连接javasctipt客户端,所以我转而使用“AndroidSync”库在Android客户端上工作。 我发现的事实是,Android客户端(我想其他客户端也是如此)在服务器处理订阅请求后没有收

  • 我正在尝试编写一个Spring服务,它订阅一个外部只读STOMP代理,并读取/处理它发布的消息。 铁路公司将消息推送到主题“/topic/TRAIN\u MVT\u ALL\u TOC”。我可以成功地连接到主题,但似乎无法将侦听器实例化为其消息。 我已经设置了一个Spring@Configuration类来连接它,在运行应用程序之后,它似乎连接正确。 我还创建了消息处理例程,使用@Message映

  • 微信文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.addTemplate.html 组合模板并添加至帐号下的个人模板库 $tid = 563; // 模板标题 id,可通过接口获取,也可登录小程序后台查看获取 $kidLi

  • 开普勒消息目前分为三大类:公告,告警和通知。 通知中根据不同的操作事件类型,分为十几个事件。每个事件都跟项目操作相关。便于接收项目操作变更的通知。 分类 事件 公告 Alarm 告警 Proclaim 通知 Build,Apply,Audit,Delete,Rollback,Logging,Reboot,Command,Storage,Extend... 订阅界面: 用户中心,点击头像,下拉菜单→

  • 我使用Spring的STOMP over WebSocket实现与一个全功能的ActiveMQ代理。当用户向主题订阅时,在成功订阅之前必须通过一些权限逻辑。我使用ChannelInterceptor应用权限逻辑,如下所示: WebSocketConfig。爪哇: WebSocketSecurityConfig.java: MySubscriptionInterceptor。爪哇: 当没有足够权限的