• vue实现stompjs+websocket和后端通信(二)


            vue项目的搭建在这里就不说了,网上有很多教程。大家自行百度。前端使用stomp+websocket有很多的实现版本。这里只讲@stomp/stompjs方式实现。

    导入

    使用@stomp/stompjs需要执行安装命令:

    import Stomp from '@stomp/stompjs';

     然后在组件中引入即可,这里需要注意的是,可能由于版本不一致,会导致引入的方式不一致。但是主要是以下两种方式中的一种

    import { Client, Stomp} from '@stomp/stompjs';

    或者
    import Stomp from '@stomp/stompjs';

     连接服务器

            连接服务器需要用到connect()方法。该方法有一个基本的成功时的回调函数

    1. var connect_success_callback = function() {
    2. // called back after the client is connected and
    3. authenticated to the STOMP server
    4. };

      connect()方法接受一个可选的参数(error_callback),当客户端不能连接上服务端时,这个回调函数error_callback会被调用,该函数的参数为对应的错误对象。

    1. var error_callback = function(error) {
    2. // display the error's message header:
    3. alert(error.headers.message);
    4. };
    '
    运行
    1. // 创建Stomp客户端实例
    2. let stompClient = Stomp.client('ws://localhost:7000/websocket-demo/stmpwebsocket');
    3. // 连接WebSocket
    4. stompClient.connect(frame => {
    5. console.log('Connected: ' + frame);
    6. //这里表示已经连接成功
    7. }, error => {
    8. console.error('STOMP error:', error);
    9. });

            connect()方法可以传入两个参数,用来做用户认证:用户的登录和密码凭证。在大多数情况下,connect()方法可接受不同数量的参数来提供简单的API:

    1. stompClient.connect(login, passcode, connectCallback);
    2. stompClient.connect(login, passcode, connectCallback, errorCallback);
    3. stompClient.connect(login, passcode, connectCallback, errorCallback, host);

      loginpasscode是strings,connectCallbackerrorCallback则是functions。(有些brokers(代理)还需要传递一个host(String类型)参数。)

            有时候我们的连接没有专门的用户名和密码,都是在原有的已经认证的基础上进行连接,例如token,所以我们需要将token传给后端:这样我们需要一个http类似的请求头实现方式。stomp也支持hear的参数

    1. stompClient.connect(headers, connectCallback);
    2. stompClient.connect(headers, connectCallback, errorCallback);

    headermap形式,connectCallbackerrorCallback为functions。

    需要注意:如果你使用上述这种方式,那就需要自行在headers添加loginpasscode(甚至host):

    1. var headers = {
    2. login: 'username',
    3. passcode: 'mypasscode',
    4. token: 'my-client-id'
    5. };
    6. stompClient.connect(headers, connectCallback);

    断开连接

            断开连接使用的时disconnect()方法,该方法接受一个回调函数

    1. stompClient.disconnect(function() {
    2. alert("See you next time!");
    3. };

    心跳保活

            如果STOMP broker(代理)接收STOMP 1.1版本的帧,heart-beating是默认启用的。

            heart-beating也就是频率,incoming是接收频率,outgoing是发送频率。通过改变incoming和outgoing可以更改客户端的heart-beating(默认为10000ms)。heart-beating是利用window.setInterval()去规律地发送heart-beats或者检查服务端的heart-beats。

    1. stompClient.heartbeat.outgoing = 20000;
    2. // client will send heartbeats every 20000ms
    3. stompClient.heartbeat.incoming = 0;
    4. // client does not want to receive heartbeats
    5. // from the server

     消息发送

            消息发送使用send()方法。这个方法必须有一个参数,用来描述对应的STOMP的目的地。另外可以有两个可选的参数:headersobject类型包含额外的信息头部;body,一个String类型的参数。

    stompClient.send(describetion, headers,messageBody)

    消息订阅和接收

             stomp的数据订阅和接收是同时的,订阅方法需要传入一个数据处理回调函数,函数有且只有一个参数,参数中包含了服务器发送的数据。且该方法会返回一个Promise对象,用于取消数据订阅。

    1. //获取订阅结果用于取消订阅
    2. let pushSubscriptionPromise = stompClient.subscribe('subscribePath', message => {
    3. // 处理接收到的消息
    4. console.log('收到消息', message.body);
    5. });

    取消订阅

            数据的取消订阅使用订阅方法返回的对象调用unSubscribe()即可

    pushUserSubscriptionPromise.unsubscribe()

     消息确认ack

            在收到服务端的数据之后,我们可能需要给后端一个ack'消息,用于告诉后端我们已经收到了消息,这个机制在传输一些很重要的信息是有必要的。

    1. //获取订阅结果用于取消订阅
    2. let pushSubscriptionPromise = stompClient.subscribe('subscribePath', message => {
    3. // 处理接收到的消息
    4. console.log('收到消息', message.body);
    5. / 发送ACK确认消息
    6. stompClient.ack(message);
    7. });

            stompClient.ack(message)方法用于发送一个ACK确认,表示我们已经收到并处理了ID为message.headers['message-id']的消息。如果你需要显式指定消息ID,可以这样做:

    stompClient.ack(message.headers['message-id']);

    以上就是使用@stomp/stompjs。

    以下是一个完整的组件代码。可直接复制到一个已经搭建好的vue项目上测试。请忽略极其难看的ui页面。

    1. <template>
    2. <div class="f_c float_l">
    3. <div class="m_10 float_l">
    4. <el-input class='input_common' v-model="websocketPath" placeholder="后端websocket地址:http://ip:port/context/websocket-point" >el-input>
    5. <el-input class='input_common' v-model="userId" placeholder="请输入用户名" >el-input>
    6. <el-button v-if="!connected" @click=" connectWebsocket" >连接el-button>
    7. <el-button v-else @click="disConnectWebsocket" >断开el-button>
    8. div>
    9. <el-divider />
    10. <div class="f_c" v-if="connected">
    11. <div>
    12. <el-input class='input_common' v-model="messageUrl" placeholder="请输入消息地址:/sendMessage">el-input>
    13. <el-button @click="sendMessage" v-if="connected">发送el-button>
    14. div>
    15. <el-input class='input_common mt_10' v-model="message" type="textarea" :rows="2" placeholder="请输入需要发送的消息">el-input>
    16. div>
    17. <el-divider />
    18. <div class="f_c m_10 float_l" v-if="connected">
    19. <div class="float_l">
    20. <el-input class='input_common' v-model="subscribePath" placeholder="请输入监听地址:/subscribe/id">el-input>
    21. <el-button @click="subscribeTopic" v-if="!subscribed">广播订阅el-button>
    22. <el-button @click="unSubscribeTopic" v-else>取消订阅el-button>
    23. div>
    24. <div class="m_10 f_c">
    25. <span class="float_l">收到消息span>
    26. <span style="border: aqua; width: 500px; height: 100px">{{receiveMessage}}span>
    27. div>
    28. div>
    29. <div class="f_c m_10 float_l" v-if="connected">
    30. <div class="float_l">
    31. <el-input class='input_common' v-model="userSubscribePath" placeholder="请输入监听地址:/subscribe/id">el-input>
    32. <el-button @click="subscribeUserTopic" v-if="!userSubscribed">用户订阅el-button>
    33. <el-button @click="unUserSubscribeTopic" v-else>取消订阅el-button>
    34. div>
    35. <div class="m_10 f_c">
    36. <span class="float_l">收到消息span>
    37. <span style="border: aqua; width: 500px; height: 100px">{{receiveUserMessage}}span>
    38. div>
    39. div>
    40. div>
    41. template>
    42. <script>
    43. import { Client, Stomp} from '@stomp/stompjs';
    44. export default {
    45. name: "index",
    46. data(){
    47. return {
    48. websocketPath:'localhost:7000/websocket-demo/stmpwebsocket',
    49. userId:'123456789',
    50. subscribePath:'/topic/targetSubscribe',
    51. receiveMessage:'',
    52. userSubscribePath:'/user/queue/targetUser',
    53. receiveUserMessage:'',
    54. messageUrl:'/message/stomp/springUserMessage/987654321',
    55. message:'',
    56. connected: false,
    57. subscribed: false,
    58. userSubscribed:false,
    59. stompClient:null,
    60. pushSubscriptionPromise: null,
    61. pushUserSubscriptionPromise: null
    62. }
    63. },
    64. methods:{
    65. connectWebsocket(){
    66. if(!this.websocketPath){
    67. this.$message.error("请先填写websocket地址信息")
    68. return
    69. }
    70. if(!this.userId){
    71. this.$message.error("请先填写用户信息")
    72. return
    73. }
    74. // 创建Stomp客户端实例
    75. this.stompClient = Stomp.client('ws://' + this.websocketPath);
    76. //请求头
    77. let headers = {
    78. 'userId': this.userId
    79. }
    80. // 连接WebSocket
    81. this.stompClient.connect(headers, frame => {
    82. console.log('Connected: ' + frame);
    83. this.connected = true
    84. }, error => {
    85. console.error('STOMP error:', error);
    86. });
    87. },
    88. sendMessage(){
    89. if(!this.message || !this.messageUrl){
    90. this.$message.error("请先填写websocket地址和消息内容信息")
    91. return
    92. }
    93. let msg = { message: this.message };
    94. console.log("数据发送:", this.messageUrl, msg)
    95. this.stompClient.send(this.messageUrl, {'aaaaaa': 'aaaaaaaaa'}, JSON.stringify(msg));
    96. },
    97. onceSubscribe(){
    98. this.stompClient.subscribe('/message/subscribe/1232131321', function(message) {
    99. console.log('onceSubscribe-Message: ' + message.body);
    100. })
    101. },
    102. subscribeTopic(){
    103. if(!this.subscribePath){
    104. this.$message.error("请先填写订阅地址")
    105. return
    106. }
    107. // 订阅某个路径
    108. let number = 1
    109. this.subscribed = true
    110. //获取订阅结果用于取消订阅
    111. this.pushSubscriptionPromise = this.stompClient.subscribe(this.subscribePath, message => {
    112. // 处理接收到的消息
    113. console.log('收到消息', message);
    114. let nowMessage = '第' + number + '次收到订阅的消息:' + JSON.stringify(JSON.parse(message.body)) + '\r\n';
    115. this.receiveMessage += nowMessage;
    116. number ++;
    117. });
    118. },
    119. subscribeUserTopic(){
    120. if(!this.userSubscribePath){
    121. this.$message.error("请先填写用户的订阅地址")
    122. return
    123. }
    124. // 订阅某个路径
    125. let number = 1
    126. this.userSubscribed = true
    127. //获取订阅结果用于取消订阅
    128. this.pushUserSubscriptionPromise = this.stompClient.subscribe(this.userSubscribePath, message => {
    129. // 处理接收到的消息
    130. console.log('收到消息', message);
    131. let nowMessage = '第' + number + '次收到订阅的消息:' + JSON.stringify(JSON.parse(message.body)) + '\r\n';
    132. this.receiveUserMessage += nowMessage;
    133. number ++;
    134. // 发送ACK确认消息
    135. this. stompClient.ack(message);
    136. });
    137. },
    138. unSubscribeTopic(){
    139. // 订阅某个路径
    140. this.pushSubscriptionPromise.unsubscribe();
    141. this.subscribed = false;
    142. this.receiveMessage = ''
    143. },
    144. unUserSubscribeTopic(){
    145. // 订阅某个路径
    146. this.pushUserSubscriptionPromise.unsubscribe();
    147. this.userSubscribed = false;
    148. this.receiveUserMessage = ''
    149. },
    150. disConnectWebsocket(){
    151. if (this.stompClient != null) {
    152. // 关闭连接
    153. this.stompClient.disconnect()
    154. this.stompClient = null
    155. this.connected = false
    156. this.subscribed = false
    157. this.userSubscribed = false
    158. this.receiveMessage = ''
    159. this.receiveUserMessage = ''
    160. }
    161. },
    162. beforeDestroy(){
    163. if(this.stompClient != null){
    164. this.stompClient.disconnect()
    165. this.stompClient = null
    166. this.connected = false
    167. this.subscribed = false
    168. this.userSubscribed = false
    169. this.receiveMessage = ''
    170. this.receiveUserMessage = ''
    171. }
    172. }
    173. }
    174. }
    175. script>
    176. <style scoped>
    177. style>
  • 相关阅读:
    Node当中的事件循环
    css 优惠券
    EasyExcel复杂表头导出(一对多)升级版
    论坛介绍|COSCon'23 大数据(D)
    代码随想录算法训练营第二十七天 | LeetCode 93. 复原 IP 地址、78. 子集、90. 子集 II
    接口自动化测试工具大全
    Java_异常详解
    Node.js 22 发布,原生支持 WebSocket 客户端
    用调试来帮你分析并拿捏折半插入排序算法的流程
    这么多年 Java 白学了,原来我连个 printf 都不会
  • 原文地址:https://blog.csdn.net/qq_34484062/article/details/139473651