SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息
SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息
参考:
1、https://www.mchweb.net/index.php/dev/887.html
3、https://blog.csdn.net/yingxiake/article/details/51224569
使用场景
广播模式 :使用场景:给所有连接了这个通道的客户端发送消息。
- convertAndSend()
- @SendTo
点对点模式 :使用场景:单独给当前用户发送消息。
下面两种方式,都默认加了一个前缀:/user
convertAndSendToUser()
@SendToUser
一、后端SpringBoot + WebSocket基础配置
1、导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、配置config
- 细节:必须配置跨域。低版本的SpringBoot(2.1.5.RELEASE 就不行)不行,需要使用高版本。低版本的解决方案还未找到。
- 跨域配置使用:.setAllowedOriginPatterns("*")。。不能使用:.setAllowedOrigins("*")
package com.cc.ws.config;
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;
/**
* <p>@EnableWebSocketMessageBroker 的作用</p>
* <li>注解开启使用STOMP协议来传输基于代理(message broker)的消息,</li>
* <li>这时控制器支持使用 @MessageMapping,就像使用 @RequestMapping一样</li>
* @author cc
*
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/** <p>启动简单Broker</p>
* <p>表示客户端订阅地址的前缀信息,也就是客户端接收服务端消息的地址的前缀信息</p>
* <p>代理的名字:都是自定义的</p>
*
* /user 点对点(默认也是/user,可以自定义,但是必须和setUserDestinationPrefix中的设置一致)
* /topic1 广播模式1
* /topic2 广播模式2
*
* /mass 广播模式:群发
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker(
"/user", "/topic1", "/topic2", "/mass"
);
// 点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是 /user/
// 注意,这里必须和上面设置的Broker:/user 一致(两个都可以自定义,但必须一致)。否则连接不上
registry.setUserDestinationPrefix("/user/");
// 指服务端接收地址的前缀,意思就是说客户端给服务端发消息的地址的前缀
// registry.setApplicationDestinationPrefixes("/socket");
}
/**
* 这个方法的作用是添加一个服务端点,来接收客户端的连接。
* registry.addEndpoint("/socket")表示添加了一个/socket端点,客户端(前端)就可以通过这个端点来进行连接。
* withSockJS()的作用是开启SockJS支持。
* @param registry registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册一个STOMP的endpoint端点,并指定使用SockJS协议
// 前端使用这个地址连接后端 WebSocket接口
registry.addEndpoint("/broadcast", "/point")
// 允许所有源跨域。还可以指定ip配置:http://ip:*
// 低版本的SpringBoot(2.1.5.RELEASE 就不行)不行
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
3、启动类,配置定时器
- @EnableScheduling
@SpringBootApplication
@EnableScheduling
public class WebSocketDemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebSocketDemoApplication.class, args);
}
}
二、前端基础配置
let socket1 = new SockJS('http://服务器ip:服务器端口/broadcast');
let stompClient1 = Stomp.over(socket1);//广播模式
stompClient1.connect({}, (frame) => {
stompClient1.subscribe('/topic1/', (message) => {
console.log(message.body);
});
});
三、后端不接收,只发送
使用spring Scheduled 定时发送消息
直接使用:SimpMessagingTemplate 的 convertAndSend广播模式 和 convertAndSendToUser点对点模式
1、后端
- 注意点对点发送:
convertAndSendToUser的默认前缀(/user)是在WebSocketConfig配置文件中配置的。
代码:
@Resource
private SimpMessagingTemplate simpMsgTemp;
/** 广播推送消息1:会发送给所有连接了 topic1 这个通道的客户端。
* topic1:在Broker中配置
**/
@Scheduled(cron = "0/1 * * * * ?")
public void getSocket(){
String msg = String.format("%s 的第 %s 个消息", "topic1", LocalDateTime.now().getSecond());
log.info("{}",msg);
simpMsgTemp.convertAndSend("/topic1/", msg);
}
/** 广播推送消息2:多指定一个uri。相当于另一条通道(推荐使用)
* <li>自定义url后缀,还可以实现用户和用户单点发送。</li>
* topic2:在Broker中配置
* custom:是自定义的
*/
@Scheduled(cron = "0/1 * * * * ?")
public void getSocketUser(){
String msg = String.format("topic2 的第 %s 个消息", LocalDateTime.now().getSecond());
log.info("{}",msg);
simpMsgTemp.convertAndSend("/topic2/custom" ,msg);
}
/**点对点发送 convertAndSendToUser(第一个参数:一般是用户id)
* -> 假如用户id是1。用用户id是1的在两个地方登陆了客户端(比如不同的浏览器登陆同一个用户),
* -> convertAndSendToUser会把消息发送到用户1登陆的两个客户端中
* 发送到:/user/{userId}/cs 下。cs是自定义的,且必须自定义一个。
*/
@Scheduled(cron = "0/1 * * * * ?")
public void pointToPoint(){
//这个用户id是后端获取的当前登陆的用户id
String userId = "123";
String msg = String.format("点对点:第 %s 个消息。用户id:%s", LocalDateTime.now().getSecond(), userId);
log.info("{}",msg);
//发送
simpMsgTemp.convertAndSendToUser(userId,"/cs/" ,msg);
}
2、前端
- 注意点对点的接收方式,用户id需要取出前端存的用户id
//这样才能同时接收后端来的三套不同通道的消息。
// broadcast 和后端:registerStompEndpoints中的配置必须一致
// point 和后端:registerStompEndpoints中的配置必须一致
// broadcast、point 也可以只用一个,这里只是为了好区分。
let socket1 = new SockJS('http://yourIp:端口/broadcast');
let socket2 = new SockJS('http://yourIp:端口/broadcast');
let socket3 = new SockJS('http://yourIp:端口/point');
// console.log("wb:" + socket)
let stompClient1 = Stomp.over(socket1);
let stompClient2 = Stomp.over(socket2);
let stompClient3 = Stomp.over(socket3);
// ----------------广播模式1--------------------
stompClient1.connect({}, (frame) => {
console.log('-----------frame1', frame)
stompClient1.subscribe('/topic1/', (message) => {
console.log(message.body);
this.msg = message.body;
// console.log(JSON.parse(message.body));
});
});
// ----------------广播模式2--------------------
stompClient2.connect({}, (frame) => {
console.log('-----------frame2', frame)
stompClient2.subscribe('/topic2/custom', (message) => {
console.log(message.body);
this.user = message.body;
// console.log(JSON.parse(message.body));
});
});
// ----------------点对点模式--------------------
//前端获取的 userId
let userId = '123';
//连接WebSocket服务端
stompClient3.connect({},(frame) => {
console.log('Connected:' + frame);
stompClient3.subscribe('/user/' + userId + '/cs/',
(response) => {
this.peer = response.body;
});
});
四、后端接收、接收后再发送
- 也可以只接收消息,不发送。看业务需求。
- 使用 @MessageMapping 接收前端发送过来的消息
- 使用:@SendTo 广播模式、@SendToUser 点对点模式
- 使用:SimpMessagingTemplate 的 convertAndSend广播模式 和 convertAndSendToUser 点对点模式
1、后端
@Resource
private SimpMessagingTemplate simpMsgTemp;
/** <p>广播模式一、接收前端的消息,处理后给前端返回一个消息。</p>
* <li>后端 把消息处理后 发送到 /mass/getResponse 路径下</li>
* <ol>
* <li>@MessageMapping("/massRequest1") :作用:接收前端来的消息。类似于@RestController</li>
* <li>@SendTo("/mass/getResponse1"):作用跟convertAndSend类似,广播发给与该通道相连的客户端。SendTo 发送至 Broker 下的指定订阅路径 </li>
* <li>@SendToUser("/mass/getResponse1"):作用跟convertAndSendToUser类似,定点发送。SendTo 发送至 Broker 下的指定订阅路径 </li>
* <li>/mass 必须在配置文件配置</li>
* <li>/getResponse1 自定义的后缀</li>
* </ol>
*/
@MessageMapping("/massRequest1")
@SendTo("/mass/getResponse1")
public String mass1(String chatRoomRequest){
//处理前端消息……
log.info("前端消息:{}",chatRoomRequest);
//返回消息
return "@SendTo 广播一(单次) 后端处理完成!";
}
/** 广播模式二、接收前端的消息,可以多次给前端发消息
* <li>/mass 必须在配置文件配置</li>
* <li>/getResponse2 自定义的后缀</li>
*/
@MessageMapping("/massRequest2")
public void mass2(String chatRoomRequest){
log.info("前端的消息:{}",chatRoomRequest);
for (int i = 0; i < 5; i++) {
String msg = "后端处理后的 广播二(多次):" + i;
simpMsgTemp.convertAndSend("/mass/getResponse2", msg);
}
simpMsgTemp.convertAndSend("/mass/getResponse2",
"后端处理后的 广播二(多次),后端处理完成!");
}
/** <p>点对点一、接收前端消息,只能返回一次消息(必须登陆系统才能使用。)</p>
* <li>只有发送原始消息的客户端才会收到响应消息,而不是所有连接的客户端都会收到响应消息。</li>
* <li>/alone/getResponse1:自定义的,不需要在配置文件配置。</li>
*
* <p>@SendToUser</p>
* <li>默认该注解前缀为 /user</li>
* <li>broadcast属性,表明是否广播。就是当有同一个用户登录多个session时,是否都能收到。取值true/false.</li>
*
* @param principal Principal :登陆用户的信息,需要使用spring s安全框架写入信息?
*/
@MessageMapping("/aloneRequest1")
@SendToUser("/alone/getResponse1")
public String alone1(String chatRoomRequest){
//处理前端消息……
log.info("前端消息:{}",chatRoomRequest);
//返回消息
return "@SendToUser 点对点一(单次) 后端处理完成!";
}
/** 点对点二、接收前端消息,可以多次给前端发消息
* <li>convertAndSendToUser —— 发送消息给指定用户id的</li>
* <li>如果用户1在两个地方(A/B)登陆可以客户端,并且连接了该通道,其中一个如A给后端发消息,后端返回消息,A/B两个地方都会收到消息</li>
* <ol>
* <li>@MessageMapping("/aloneRequest2") 接收前端指定用户消息,</li>
* <li>/alone/getResponse2 不用在配置文件中配置</li>
* <li>返回消息 发送到 user/{userId}/alone/getResponse2 下 (定点发送)</li>
* </ol>
*/
@MessageMapping("/aloneRequest2")
public void alone2(String chatRoomRequest){
//后端获取的当前登陆的用户的id(和前端一致)
String userId = "456";
log.info("前端的消息:{}",chatRoomRequest);
for (int i = 0; i < 5; i++) {
String msg = "后端处理后的 点对点二(多次):" + i;
simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2", msg);
}
simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2",
"后端处理后的 点对点二(多次),后端处理完成!");
}
2、前端
- 3点对点一 未实现。
//连接SockJS的 broadcast
let socket1 = new SockJS('http://yourIp:端口/broadcast');
let socket2 = new SockJS('http://yourIp:端口/broadcast');
let socket3 = new SockJS('http://yourIp:端口/point');
let socket4 = new SockJS('http://yourIp:端口/point');
//使用STMOP子协议的WebSocket客户端
let stompClient1 = Stomp.over(socket1);
let stompClient2 = Stomp.over(socket2);
let stompClient3 = Stomp.over(socket3);
let stompClient4 = Stomp.over(socket4);
//1广播模式一
stompClient1.connect({},(frame) => {
console.log('广播模式一:' + frame);
//1发送消息
stompClient1.send("/massRequest1",{},"我是前端来 广播模式一 的消息!");
//2接收消息
stompClient1.subscribe('/mass/getResponse1',(response) => {
this.broadcast1 = response.body
});
});
//2广播模式二
stompClient2.connect({},(frame) => {
console.log('广播模式二:' + frame);
//1发送消息
stompClient2.send("/massRequest2",{},"我是前端来 广播模式二 的消息");
//2接收消息
stompClient2.subscribe('/mass/getResponse2',(response) => {
this.broadcast2 = response.body
});
});
//3点对点一 :必须登陆系统才能实现。要往:Principal设置用户登陆信息才行
//1发送消息
// stompClient3.send("/aloneRequest1",{},"我是前端来 点对点一 的消息");
stompClient3.connect({},(frame) => {
console.log('点对点一1:' + frame);
stompClient3.send("/aloneRequest1",{},"我是前端来 点对点一 的消息");
//2接收消息
stompClient3.subscribe('/user/alone/getResponse1' ,(response) => {
console.log('-------response.body', response.body)
this.point1 = response.body
});
});
//4点对点二:必须获取现在登陆了的用户id,且必须和后端一致才行。
stompClient4.connect({},(frame) => {
console.log('点对点二:' + frame);
//1发送消息
stompClient4.send("/aloneRequest2",{},"我是前端来 点对点二 的消息");
//2接收消息
//前端获取的当前登陆的用户userId(和后端一致)
let userId = '456';
stompClient4.subscribe('/user/'+userId+'/alone/getResponse2',(response) => {
this.point2 = response.body
});
});
SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息的更多相关文章
- springboot集成websocket实现向前端浏览器发送一个对象,发送消息操作手动触发
工作中有这样一个需示,我们把项目中用到代码缓存到前端浏览器IndexedDB里面,当系统管理员在后台对代码进行变动操作时我们要更新前端缓存中的代码怎么做开始用想用版本方式来处理,但这样的话每次使用代码 ...
- SpringBoot整合WebSocket实现前后端互推消息
小编写这篇文章是为了记录实现WebSocket的过程,受不了啰嗦的同学可以直接看代码. 前段时间做项目时设计了一个广播的场景,具体业务不再赘述,最终要实现的效果就是平台接收到的信息实时发布给所有的用户 ...
- springboot支持webSocket和stomp实现消息订阅通知示例
先导入支持websocket的jar包,这里用Gradle构建的项目: dependencies { compile('org.springframework.boot:spring-boot-sta ...
- 基于springboot工程浅谈整合rabbitmq怎么样防止消息发送mq不丢失和消费mq的消息防止丢失
本文只针对springboot整合rabbitmq的消息防丢失,话不多说,上干货.... 设置发送mq消息不丢失实现思路 执行的方案: 第一步,要对队列,消息以及交换机进行持久化操作(保存到物理磁盘中 ...
- 启动任务StartTask() 发送完消息队列 自己删除,接收方一直显示数据 用OSQFlush(Str_Q); //清空消息队列 下面纠结接收不到了 哈哈
在建立工程的时候,启动任务StartTask() 启动了任务MyTask(),也建立了消息队列,然后发送消息队列,发送完自己删除了自己,在接收方一直能接受到数据???为何??? 因为我们的消息队列未 ...
- 【Java分享客栈】SpringBoot整合WebSocket+Stomp搭建群聊项目
前言 前两周经常有大学生小伙伴私信给我,问我可否有偿提供毕设帮助,我说暂时没有这个打算,因为工作实在太忙,现阶段无法投入到这样的领域内,其中有两个小伙伴又问到我websocket该怎么使用,想给自己的 ...
- SpringBoot集成WebSocket【基于STOMP协议】进行点对点[一对一]和广播[一对多]实时推送
原文详细地址,有点对点,还有广播的推送:https://blog.csdn.net/ouyzc/article/details/79884688 下面是自己处理的一些小bug 参考原文demo,结合工 ...
- SpringBoot 整合 WebSocket
SpringBoot 整合 WebSocket(topic广播) 1.什么是WebSocket WebSocket为游览器和服务器提供了双工异步通信的功能,即游览器可以向服务器发送消息,服务器也可以向 ...
- SpringBoot集成WebSocket【基于纯H5】进行点对点[一对一]和广播[一对多]实时推送
代码全部复制,仅供自己学习用 1.环境搭建 因为在上一篇基于STOMP协议实现的WebSocket里已经有大概介绍过Web的基本情况了,所以在这篇就不多说了,我们直接进入正题吧,在SpringBoot ...
- SpringBoot基于websocket的网页聊天
一.入门简介正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它?其实我们虽然有http协议,但是它有一个缺 ...
随机推荐
- 手机,IPAD查看eagle素材库
把eagle素材库塞进手机里是一种什么样的体验?手机和ipad也能查看eagle素材库,随时随地查询浏览素材. 先看使用截图 实现原理: 在任意电脑,服务器或者nas中安装PicHome系统.在Pic ...
- nginx location块
location块在server块中使用,它的作用是根据客户端请求URL去定位不同的应用. 匹配格式 作用 location = /uri = 表示精确匹配,只有完全匹配上才能生效 location ...
- java 控制台 输出进度条
效果 代码 public static void main(String[] args) { int total = 100; for (int i = 0; i < total; i++) ...
- KingbaseES 最老事务阻止vacuum freeze
前言 最近生产环境发生几次由于长事务导致表.库年龄没法回收的情况.我们要规避这种情况的发生,不要等发生了再去强制中断会话连接.当数据库中存在最老事务版本xmin,那么早于他的快照可以被标记为froze ...
- Lab2:System Call
trace 该系统调用程序,可以跟踪其他的系统调用命令,该系统调用的形参为一个整数掩码.其具体实参为1 << sys_call所得到的整数值,sys_call是一个系统调用指令在内核中定义 ...
- ET介绍——分布式Actor模型
Actor模型 Actor介绍 在讨论Actor模型之前先要讨论下ET的架构,游戏服务器为了利用多核一般有两种架构,单线程多进程跟单进程多线程架构.两种架构本质上其实区别不大,因为游戏逻辑开发都需要用 ...
- #AC自动机#洛谷 2444 [POI2000]病毒
题目 给定若干01串,问是否存在无限长的01串任意子串不是给定的若干串 分析 如果在AC自动机上跳到了访问过的前缀即代表存在一个循环可以无限跳, 在AC自动机上记录哪些状态是不能访问的,在AC自动机上 ...
- Matplotlib绘图设置--- 图例设置
plt.legend()和ax.legend()参数设置 自动会将每条线的标签与其风格.颜色进行匹配. plt.legend(*args, **kwargs) Place a legend on th ...
- C语言 05 变量与常量
变量 变量就像在数学中学习的 x,y 一样,可以直接声明一个变量,并利用这些变量进行基本的运算,声明变量的格式为: 数据类型 变量名称 = 初始值;(其中初始值可以不用在定义变量时设定) = 是赋值操 ...
- ArkUI,更高效的框架设计
原文:https://mp.weixin.qq.com/s/uSIzuBby7Z92drNDmejKXw,点击链接查看更多技术内容. 上期文章我们讲到了ArkUI的三大特性,同时提到了Ark ...