首页 > 其他分享 >Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》

时间:2022-11-07 18:05:34浏览次数:56  
标签:实战 WebSocket String stompClient content 整合 var document public


前言

websocket ,对于我来说已经是老朋友了。 

 很久很久以前,我写过两篇websocket 相关的文章。

  一篇极简风,最最最基础的方式整合websocket :

《SpringBoot 整合WebSocket 简单实战案例》

地址: ​​SpringBoot 整合WebSocket 简单实战案例_默默不代表沉默-CSDN博客_springboot websocket​​

一篇极限风,最最最完善的方式整合websocket (stomp+rabbitmq处理负载):

 《Springboot 整合Websocket,Stomp协议,使用rabbitmq做消息代理,消息缓存

 地址: ​​Springboot 整合Websocket+Stomp协议+RabbitMQ做消息代理 实例教程_默默不代表沉默-CSDN博客_rabbitmq stomp协议​​

但是按照最近看官们给我反应情况来看, 一个极简不符合需求,因为看官们虽然想简单,但是也想用stomp。

然而那个极限的呢,又太复杂,看官们不乐意去整合rabbitmq。

那么,这篇文章的意义就出来了。
 

正文

本篇内容:

1.后端整合websocket (STOMP协议)

2.群发、指定单发

3.前端简单页面示例(接收、发送消息)

事不宜迟,开始敲代码。

先看下这次实战案例项目结构:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_websocket

1. pom.xml 核心依赖的导入:
 

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

2.application.yml  (我就单纯设置一下端口)
 

server:
port: 9908

3.WebSocketConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;


/**
* @Author JCccc
* @Description EnableWebSocketMessageBroker-注解开启STOMP协议来传输基于代理的消息,此时控制器支持使用@MessageMapping
* @Date 2021/6/30 8:53
*/

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//topic用来广播,user用来实现点对点
config.enableSimpleBroker("/topic", "/user");
}

/**
* 开放节点
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册两个STOMP的endpoint,分别用于广播和点对点


//广播
registry.addEndpoint("/publicServer").setAllowedOrigins("*").withSockJS();

//点对点
registry.addEndpoint("/privateServer").setAllowedOrigins("*").withSockJS();
}


}

4.推送消息的实体类 Message.java

/**
* @Author JCccc
* @Description
* @Date 2021/8/20 9:26
*/
public class Message {

/**
* 消息编码
*/
private String code;

/**
* 来自(保证唯一)
*/
private String form;

/**
* 去自(保证唯一)
*/
private String to;

/**
* 内容
*/
private String content;

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getForm() {
return form;
}

public void setForm(String form) {
this.form = form;
}

public String getTo() {
return to;
}

public void setTo(String to) {
this.to = to;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

5.前端简单调试页面 

① publicExample.html 监听广播消息的测试页面

<html>
<head>
<meta charset="UTF-8">
<title>等系统推消息</title>
<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.0.min.js"
integrity="sha256-JAW99MJVpJBGcbzEuXk4Az05s/XyDdBomFqNlM3ic+I=" crossorigin="anonymous"></script>

<script type="text/javascript">
var stompClient = null;

function setConnected(connected) {
document.getElementById("connect").disabled = connected;
document.getElementById("disconnect").disabled = !connected;
$("#response").html();
}

function connect() {

var socket = new SockJS("http://localhost:9908/publicServer");
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/all', function (response) {
var responseData = document.getElementById('responseData');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(response.body));
responseData.appendChild(p);
});
},{});
}

function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}

function sendMsg() {
var content = document.getElementById('content').value;
stompClient.send("/all",{},JSON.stringify({'content': content}));
}
</script>
</head>
<body onl oad="disconnect()">
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div>
<div>
<labal>连接广播频道</labal>
<button id="connect" onclick="connect();">Connect</button>
<labal>取消连接</labal>
<button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>
</div>
<div id="conversationDiv">
<labal>广播消息</labal>
<input type="text" id="content"/>
<button id="sendMsg" onclick="sendMsg();">Send</button>

</div>
<div>
<labal>接收到的消息:</labal>
<p id="responseData"></p>

</div>

</div>

</body>
</html>

简析: 

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_02

趁热打铁,我们模拟系统后端给前端推送广播消息,通过接口模拟:
 

TestController.java

/**
* @Author JCccc
* @Description
* @Date 2021/8/20 8:53
*/
@Controller
public class TestController {
@Autowired
public SimpMessagingTemplate template;

/**
* 广播
*
* @param msg
*/
@ResponseBody
@RequestMapping("/pushToAll")
public void subscribe( @RequestBody Message msg) {
template.convertAndSend("/topic/all", msg.getContent());
}
}

简析:

我们推送消息,直接用 SimpMessagingTemplate ,

用的是convertAndSend 广播方式推送到对于的主题目的地 destination 。

(可以看到其实还有convertAndSendToUser ,不着急,后面会说,这是发送给某个连接用户的)

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_03

 直接把项目跑起来,打开页面开始测试:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring boot_04

 我们先点击connect ,连接成功:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_05

可以看到实际上stomp.min.js 最终也是转化成为 ws/wss这种方式成功连接:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_06

调用测试接口,推送广播消息:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_rabbitmq_07

 

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring_08

 在console其实也能看到:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_09

 广播功能就到这,接下来是 点对点。

前端页面:

privateExample.html

<html>
<head>
<meta charset="UTF-8">
<title>聊起来</title>
<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://code.jquery.com/jquery-3.2.0.min.js"
integrity="sha256-JAW99MJVpJBGcbzEuXk4Az05s/XyDdBomFqNlM3ic+I=" crossorigin="anonymous"></script>

<script type="text/javascript">
var stompClient = null;

function setConnected(connected) {
document.getElementById("connect").disabled = connected;
document.getElementById("disconnect").disabled = !connected;
$("#response").html();
}

function connect() {
var socket = new SockJS("http://localhost:9908/privateServer");
stompClient = Stomp.over(socket);
stompClient.heartbeat.outgoing = 20000;
// client will send heartbeats every 20000ms
stompClient.heartbeat.incoming = 0;
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/' + document.getElementById('user').value + '/message', function (response) {
var responseData = document.getElementById('responseData');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(response.body));
responseData.appendChild(p);
});


});

}

function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");

}

function sendMsg() {
var headers = {
login: 'mylogin',
passcode: 'mypasscode',
// additional header
'accessToken': 'HWPO325J9814GBHJF933'
};
var content = document.getElementById('content').value;
var to = document.getElementById('to').value;
stompClient.send("/alone", {'accessToken': 'HWPO325J9814GBHJF933'}, JSON.stringify({
'content': content,
'to': to
}));
}
</script>
</head>
<body onl oad="disconnect()">
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div>
<div>
<labal>连接用户</labal>
<input type="text" id="user"/>
<button id="connect" onclick="connect();">Connect</button>

</div>

<div>
<labal>取消连接</labal>
<button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>
</div>

<div id="conversationDiv">
<labal>发送消息</labal>
<div>
<labal>内容</labal>
<input type="text" id="content"/>
</div>
<div>
<labal>发给谁</labal>
<input type="text" id="to"/>
</div>
<button id="sendMsg" onclick="sendMsg();">Send</button>

</div>
<div>
<labal>接收到的消息:</labal>
<p id="responseData"></p>

</div>
</div>

</body>
</html>

简析:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring boot_10

趁热打铁,我们模拟系统后端给前端推送点对点消息(指定某个用户),通过接口模拟:

/**
* 点对点
*/
@ResponseBody
@RequestMapping("/pushToOne")
public void queue(@RequestBody Message msg) {
System.out.println("进入方法");
/*使用convertAndSendToUser方法,第一个参数为用户id,此时js中的订阅地址为
"/user/" + 用户Id + "/message",其中"/user"是固定的*/
template.convertAndSendToUser(msg.getTo(), "/message", msg.getContent());

}

用的是convertAndSendToUser 推送到指定的用户 ,对于的主题目的地 destination(/message) 

也许看到这里,你会觉得很奇怪,为什么我们推的主题是 /message,但是前端订阅的却是
 

"/user/" + 用户Id + "/message"

我们直接看源码:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_websocket_11

 

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_rabbitmq_12

 ok,应该不用多说,代码帮我们自己拼接起来了,跟前端订阅规则保持一致。

直接跑项目,测试一下:

模拟我们连接的用户标识 19901 ,连接成功

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_javascript_13

使用postman调用我们的测试接口,模拟系统指定推送消息到 19901 这个人 :

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring_14

然后也给20011发送一下消息:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring boot_15

 然后看到对应的用户也能收到对应的消息:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_websocket_16

对点推送,广播推送,也已经完毕了 。

这种情况就是相当于使用http接口方式,去撮合后端服务做 消息推送。

其实spring还提供了一些好玩的注解,

@MessageMapping  这个注解是对称于  @EnableWebSocketMessageBroker

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_spring_17

也就是说,如果我们使用@EnableWebSocketMessageBroker ,那么我们在接口上面其实就能直接使用  @MessageMapping。

怎么用?

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_rabbitmq_18

然后前端代码里面 的使用:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_rabbitmq_19

 

 这样我们就可以通过前端直接调用相关接口了:

Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)《SpringBoot 整合WebSocket 简单实战案例》_websocket_20

个人认为其实没有必要使用这个注解,直接通过前端调用后端服务代码,我们服务端来根据Message里面 的 发送方、接收方、消息类型(点对点、广播)就可以直接完成相关也业务场景了。

ok,该篇就到此。

下一篇,给大家带来怎么解决websocket负载问题 。

标签:实战,WebSocket,String,stompClient,content,整合,var,document,public
From: https://blog.51cto.com/u_15753094/5830334

相关文章

  • 复杂软件设计之道:领域驱动设计全面解析与实战
    "IT有得聊”是机械工业出版社旗下IT专业资讯和服务平台,致力于帮助读者在广义的IT领域里,掌握更专业、实用的知识与技能,快速提升职场竞争力。 今天为您推荐一本精品图书--复......
  • APICloud实战案例:如何封装AVM组件?(以声网组件为例)
    AVM.js(Application-View-Model)是一个移动优先的高性能跨端JavaScript框架,支持一次编写多端渲染。它提供更趋近于原生的编程体验,通过简洁的模型来分离应用的用户界面、业......
  • LabVIEW+OpenVINO在CPU上部署新冠肺炎检测模型实战
    前言之前博客:【YOLOv5】LabVIEW+OpenVINO让你的YOLOv5在CPU上飞起来给大家介绍了在LabVIEW上使用openvino加速推理,在CPU上也能感受丝滑的实时物体识别。那我们今天就一起......
  • Docker容器实战十四:Docker Compose介绍
    在前面的介绍中我们都是以单个容器为例来进行演示。但在实际的生产环境中,一个应用往往会有多个组件,并分别运行在不同的容器。在这种多容器的场景下,使用Docker客户端进行管理......
  • React中常见的TypeScript定义实战
    一引沿Fiber架构是React16中引入的新概念,目的就是解决大型React应用卡顿,React在遍历更新每一个节点的时候都不是用的真实DOM,都是采用虚拟DOM,所以可以理解成fiber就是R......
  • React-hooks+TypeScript最佳实战
    ReactHooks什么是HooksReact一直都提倡使用函数组件,但是有时候需要使用state或者其他一些功能时,只能使用类组件,因为函数组件没有实例,没有生命周期函数,只有类组件才......
  • 『Python核心技术与实战』列表和元组,到底用哪一个?
    列表和元组,到底用哪一个?文章目录​​一.列表和元组区别​​​​二.列表和元组基本操作与注意事项​​​​三.列表和元组存储方式的差异​​​​四.列表和元组的性能​​......
  • Selenium3自动化测试实战--第3章 Python基础2
    3.6模组模组,一般称为类库或模块。分为标准模块和第三方库。3.6.1调用模块importtimefromtimeimporttime,sleepfromtimeimport*   #不用每个函数加tim......
  • k8s实战入门——Pod
    PodPod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。kubernet......
  • 系统整理K8S的配置管理实战-建议收藏系列
    目录一、ConfigMap1.1、创建1.1.1、from-file1.1.2、from-env-file1.1.3、from-literal1.1.4、基于yaml文件创建1.2、Pod使用ConfigMap1.2.1、valueFrom1.2.2、envFrom1.2.......