SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息 ...

打印 上一主题 下一主题

主题 867|帖子 867|积分 2601

SpringBoot实现WebSocket发送接收消息 +  Vue实现SocketJs接收发送消息

参考:

1、https://www.mchweb.net/index.php/dev/887.html
2、https://itonline.blog.csdn.net/article/details/81221103?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-121078449.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-121078449.pc_relevant_aa&utm_relevant_index=1
3、https://blog.csdn.net/yingxiake/article/details/51224569
使用场景

广播模式  :使用场景:给所有连接了这个通道的客户端发送消息。

  • convertAndSend()
  • @SendTo
点对点模式  :使用场景:单独给当前用户发送消息。

  • 下面两种方式,都默认加了一个前缀:/user
  • convertAndSendToUser()
  • @SendToUser
一、后端SpringBoot + WebSocket基础配置

1、导包
  1. <dependency>
  2.         <groupId>org.springframework.boot</groupId>
  3.         <artifactId>spring-boot-starter-websocket</artifactId>
  4. </dependency>
复制代码
2、配置config


  • 细节:必须配置跨域。低版本的SpringBoot(2.1.5.RELEASE 就不行)不行,需要使用高版本。低版本的解决方案还未找到。
  • 跨域配置使用:.setAllowedOriginPatterns("*")。。不能使用:.setAllowedOrigins("*")
  1. package com.cc.ws.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.messaging.simp.config.MessageBrokerRegistry;
  4. import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
  5. import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
  6. import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
  7. /**
  8. * <p>@EnableWebSocketMessageBroker 的作用</p>
  9. * <li>注解开启使用STOMP协议来传输基于代理(message broker)的消息,</li>
  10. * <li>这时控制器支持使用 @MessageMapping,就像使用 @RequestMapping一样</li>
  11. * @author cc
  12. *
  13. */
  14. @Configuration
  15. @EnableWebSocketMessageBroker
  16. public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  17.     /** <p>启动简单Broker</p>
  18.      * <p>表示客户端订阅地址的前缀信息,也就是客户端接收服务端消息的地址的前缀信息</p>
  19.      * <p>代理的名字:都是自定义的</p>
  20.      *
  21.      * /user     点对点(默认也是/user,可以自定义,但是必须和setUserDestinationPrefix中的设置一致)
  22.      * /topic1   广播模式1
  23.      * /topic2   广播模式2
  24.      *
  25.      * /mass     广播模式:群发
  26.      */
  27.     @Override
  28.     public void configureMessageBroker(MessageBrokerRegistry registry) {
  29.         registry.enableSimpleBroker(
  30.                 "/user", "/topic1", "/topic2", "/mass"
  31.         );
  32.         // 点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是 /user/
  33.         // 注意,这里必须和上面设置的Broker:/user 一致(两个都可以自定义,但必须一致)。否则连接不上
  34.         registry.setUserDestinationPrefix("/user/");
  35.         // 指服务端接收地址的前缀,意思就是说客户端给服务端发消息的地址的前缀
  36. //        registry.setApplicationDestinationPrefixes("/socket");
  37.     }
  38.     /**
  39.      * 这个方法的作用是添加一个服务端点,来接收客户端的连接。
  40.      * registry.addEndpoint("/socket")表示添加了一个/socket端点,客户端(前端)就可以通过这个端点来进行连接。
  41.      * withSockJS()的作用是开启SockJS支持。
  42.      * @param registry registry
  43.      */
  44.     @Override
  45.     public void registerStompEndpoints(StompEndpointRegistry registry) {
  46.         // 注册一个STOMP的endpoint端点,并指定使用SockJS协议
  47.         // 前端使用这个地址连接后端 WebSocket接口
  48.         registry.addEndpoint("/broadcast", "/point")
  49.                 // 允许所有源跨域。还可以指定ip配置:http://ip:*
  50.                 // 低版本的SpringBoot(2.1.5.RELEASE 就不行)不行
  51.                 .setAllowedOriginPatterns("*")
  52.                 .withSockJS();
  53.     }
  54. }
复制代码
3、启动类,配置定时器


  • @EnableScheduling
  1. @SpringBootApplication
  2. @EnableScheduling
  3. public class WebSocketDemoApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(WebSocketDemoApplication.class, args);
  6.     }
  7. }
复制代码
二、前端基础配置
  1.     let socket1 = new SockJS('http://服务器ip:服务器端口/broadcast');
  2.    
  3.     let stompClient1 = Stomp.over(socket1);//广播模式
  4.     stompClient1.connect({}, (frame) => {
  5.       stompClient1.subscribe('/topic1/', (message) => {
  6.         console.log(message.body);
  7.       });
  8.     });
复制代码
三、后端不接收,只发送


  • 使用spring Scheduled 定时发送消息
  • 直接使用:SimpMessagingTemplate 的 convertAndSend广播模式 和 convertAndSendToUser点对点模式
1、后端


  • 注意点对点发送:
convertAndSendToUser的默认前缀(/user)是在WebSocketConfig配置文件中配置的。
代码:
  1.     @Resource
  2.     private SimpMessagingTemplate simpMsgTemp;
  3.     /** 广播推送消息1:会发送给所有连接了 topic1 这个通道的客户端。
  4.      * topic1:在Broker中配置
  5.      **/
  6.     @Scheduled(cron = "0/1 * * * * ?")
  7.     public void getSocket(){
  8.         String msg = String.format("%s 的第 %s 个消息", "topic1", LocalDateTime.now().getSecond());
  9.         log.info("{}",msg);
  10.         simpMsgTemp.convertAndSend("/topic1/", msg);
  11.     }
  12.     /** 广播推送消息2:多指定一个uri。相当于另一条通道(推荐使用)
  13.      * <li>自定义url后缀,还可以实现用户和用户单点发送。</li>
  14.      * topic2:在Broker中配置
  15.      * custom:是自定义的
  16.      */
  17.     @Scheduled(cron = "0/1 * * * * ?")
  18.     public void getSocketUser(){
  19.         String msg = String.format("topic2 的第 %s 个消息", LocalDateTime.now().getSecond());
  20.         log.info("{}",msg);
  21.         simpMsgTemp.convertAndSend("/topic2/custom" ,msg);
  22.     }
  23.     /**点对点发送 convertAndSendToUser(第一个参数:一般是用户id)
  24.      *  -> 假如用户id是1。用用户id是1的在两个地方登陆了客户端(比如不同的浏览器登陆同一个用户),
  25.      *  -> convertAndSendToUser会把消息发送到用户1登陆的两个客户端中
  26.      * 发送到:/user/{userId}/cs 下。cs是自定义的,且必须自定义一个。
  27.      */
  28.     @Scheduled(cron = "0/1 * * * * ?")
  29.     public void pointToPoint(){
  30.         //这个用户id是后端获取的当前登陆的用户id
  31.         String userId = "123";
  32.         String msg = String.format("点对点:第 %s 个消息。用户id:%s", LocalDateTime.now().getSecond(), userId);
  33.         log.info("{}",msg);
  34.         //发送
  35.         simpMsgTemp.convertAndSendToUser(userId,"/cs/" ,msg);
  36.     }
复制代码
2、前端


  • 注意点对点的接收方式,用户id需要取出前端存的用户id
  1.     //这样才能同时接收后端来的三套不同通道的消息。
  2.     // broadcast 和后端:registerStompEndpoints中的配置必须一致
  3.     // point     和后端:registerStompEndpoints中的配置必须一致
  4.     // broadcast、point 也可以只用一个,这里只是为了好区分。
  5.     let socket1 = new SockJS('http://172.16.8.1:8099/broadcast');
  6.     let socket2 = new SockJS('http://172.16.8.1:8099/broadcast');
  7.     let socket3 = new SockJS('http://172.16.8.1:8099/point');
  8.     // console.log("wb:" + socket)
  9.     let stompClient1 = Stomp.over(socket1);
  10.     let stompClient2 = Stomp.over(socket2);
  11.     let stompClient3 = Stomp.over(socket3);
  12.     // ----------------广播模式1--------------------
  13.     stompClient1.connect({}, (frame) => {
  14.       console.log('-----------frame1', frame)
  15.       stompClient1.subscribe('/topic1/', (message) => {
  16.         console.log(message.body);
  17.         this.msg = message.body;
  18.         // console.log(JSON.parse(message.body));
  19.       });
  20.     });
  21.     // ----------------广播模式2--------------------
  22.     stompClient2.connect({}, (frame) => {
  23.       console.log('-----------frame2', frame)
  24.       stompClient2.subscribe('/topic2/custom', (message) => {
  25.         console.log(message.body);
  26.         this.user = message.body;
  27.         // console.log(JSON.parse(message.body));
  28.       });
  29.     });
  30.     // ----------------点对点模式--------------------
  31.     //前端获取的 userId
  32.     let userId = '123';
  33.     //连接WebSocket服务端
  34.     stompClient3.connect({},(frame) => {
  35.       console.log('Connected:' + frame);
  36.       stompClient3.subscribe('/user/' + userId + '/cs/',
  37.           (response) => {
  38.             this.peer = response.body;
  39.       });
  40.     });
复制代码
四、后端接收、接收后再发送


  • 也可以只接收消息,不发送。看业务需求。
  • 使用 @MessageMapping 接收前端发送过来的消息
  • 使用:@SendTo 广播模式、@SendToUser 点对点模式
  • 使用:SimpMessagingTemplate 的 convertAndSend广播模式 和 convertAndSendToUser 点对点模式
1、后端
  1.     @Resource
  2.     private SimpMessagingTemplate simpMsgTemp;
  3.     /** <p>广播模式一、接收前端的消息,处理后给前端返回一个消息。</p>
  4.      * <li>后端 把消息处理后 发送到 /mass/getResponse 路径下</li>
  5.      * <ol>
  6.      *     <li>@MessageMapping("/massRequest1") :作用:接收前端来的消息。类似于@RestController</li>
  7.      *     <li>@SendTo("/mass/getResponse1"):作用跟convertAndSend类似,广播发给与该通道相连的客户端。SendTo 发送至 Broker 下的指定订阅路径 </li>
  8.      *     <li>@SendToUser("/mass/getResponse1"):作用跟convertAndSendToUser类似,定点发送。SendTo 发送至 Broker 下的指定订阅路径 </li>
  9.      *     <li>/mass 必须在配置文件配置</li>
  10.      *     <li>/getResponse1 自定义的后缀</li>
  11.      * </ol>
  12.      */
  13.     @MessageMapping("/massRequest1")
  14.     @SendTo("/mass/getResponse1")
  15.     public String mass1(String chatRoomRequest){
  16.         //处理前端消息……
  17.         log.info("前端消息:{}",chatRoomRequest);
  18.         //返回消息
  19.         return "@SendTo 广播一(单次) 后端处理完成!";
  20.     }
  21.     /** 广播模式二、接收前端的消息,可以多次给前端发消息
  22.      * <li>/mass 必须在配置文件配置</li>
  23.      * <li>/getResponse2 自定义的后缀</li>
  24.      */
  25.     @MessageMapping("/massRequest2")
  26.     public void mass2(String chatRoomRequest){
  27.         log.info("前端的消息:{}",chatRoomRequest);
  28.         for (int i = 0; i < 5; i++) {
  29.             String msg = "后端处理后的 广播二(多次):" + i;
  30.             simpMsgTemp.convertAndSend("/mass/getResponse2", msg);
  31.         }
  32.         simpMsgTemp.convertAndSend("/mass/getResponse2",
  33.                 "后端处理后的 广播二(多次),后端处理完成!");
  34.     }
  35.     /** <p>点对点一、接收前端消息,只能返回一次消息(必须登陆系统才能使用。)</p>
  36.      * <li>只有发送原始消息的客户端才会收到响应消息,而不是所有连接的客户端都会收到响应消息。</li>
  37.      * <li>/alone/getResponse1:自定义的,不需要在配置文件配置。</li>
  38.      *
  39.      * <p>@SendToUser</p>
  40.      * <li>默认该注解前缀为 /user</li>
  41.      * <li>broadcast属性,表明是否广播。就是当有同一个用户登录多个session时,是否都能收到。取值true/false.</li>
  42.      *
  43.      * @param principal Principal :登陆用户的信息,需要使用spring s安全框架写入信息?
  44.      */
  45.     @MessageMapping("/aloneRequest1")
  46.     @SendToUser("/alone/getResponse1")
  47.     public String alone1(String chatRoomRequest){
  48.         //处理前端消息……
  49.         log.info("前端消息:{}",chatRoomRequest);
  50.         //返回消息
  51.         return "@SendToUser 点对点一(单次) 后端处理完成!";
  52.     }
  53.     /** 点对点二、接收前端消息,可以多次给前端发消息
  54.      * <li>convertAndSendToUser —— 发送消息给指定用户id的</li>
  55.      * <li>如果用户1在两个地方(A/B)登陆可以客户端,并且连接了该通道,其中一个如A给后端发消息,后端返回消息,A/B两个地方都会收到消息</li>
  56.      * <ol>
  57.      *     <li>@MessageMapping("/aloneRequest2") 接收前端指定用户消息,</li>
  58.      *     <li>/alone/getResponse2 不用在配置文件中配置</li>
  59.      *     <li>返回消息 发送到 user/{userId}/alone/getResponse2 下 (定点发送)</li>
  60.      * </ol>
  61.      */
  62.     @MessageMapping("/aloneRequest2")
  63.     public void alone2(String chatRoomRequest){
  64.         //后端获取的当前登陆的用户的id(和前端一致)
  65.         String userId = "456";
  66.         log.info("前端的消息:{}",chatRoomRequest);
  67.         for (int i = 0; i < 5; i++) {
  68.             String msg = "后端处理后的 点对点二(多次):" + i;
  69.             simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2", msg);
  70.         }
  71.         simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2",
  72.                 "后端处理后的 点对点二(多次),后端处理完成!");
  73.     }
复制代码
2、前端


  • 3点对点一 未实现。
  1.     //连接SockJS的 broadcast
  2.     let socket1 = new SockJS('http://172.16.8.7:8099/broadcast');
  3.     let socket2 = new SockJS('http://172.16.8.7:8099/broadcast');
  4.     let socket3 = new SockJS('http://172.16.8.7:8099/point');
  5.     let socket4 = new SockJS('http://172.16.8.7:8099/point');
  6.     //使用STMOP子协议的WebSocket客户端
  7.     let stompClient1 = Stomp.over(socket1);
  8.     let stompClient2 = Stomp.over(socket2);
  9.     let stompClient3 = Stomp.over(socket3);
  10.     let stompClient4 = Stomp.over(socket4);
  11.     //1广播模式一
  12.     stompClient1.connect({},(frame) => {
  13.       console.log('广播模式一:' + frame);
  14.       //1发送消息
  15.       stompClient1.send("/massRequest1",{},"我是前端来 广播模式一 的消息!");
  16.       //2接收消息
  17.       stompClient1.subscribe('/mass/getResponse1',(response) => {
  18.         this.broadcast1 = response.body
  19.       });
  20.     });
  21.     //2广播模式二
  22.     stompClient2.connect({},(frame) => {
  23.       console.log('广播模式二:' + frame);
  24.       //1发送消息
  25.       stompClient2.send("/massRequest2",{},"我是前端来 广播模式二 的消息");
  26.       //2接收消息
  27.       stompClient2.subscribe('/mass/getResponse2',(response) => {
  28.         this.broadcast2 = response.body
  29.       });
  30.     });
  31.     //3点对点一 :必须登陆系统才能实现。要往:Principal设置用户登陆信息才行
  32.     //1发送消息
  33.     // stompClient3.send("/aloneRequest1",{},"我是前端来 点对点一 的消息");
  34.     stompClient3.connect({},(frame) => {
  35.       console.log('点对点一1:' + frame);
  36.       stompClient3.send("/aloneRequest1",{},"我是前端来 点对点一 的消息");
  37.       //2接收消息
  38.       stompClient3.subscribe('/user/alone/getResponse1' ,(response) => {
  39.         console.log('-------response.body', response.body)
  40.         this.point1 = response.body
  41.       });
  42.     });
  43.     //4点对点二:必须获取现在登陆了的用户id,且必须和后端一致才行。
  44.     stompClient4.connect({},(frame) => {
  45.       console.log('点对点二:' + frame);
  46.       //1发送消息
  47.       stompClient4.send("/aloneRequest2",{},"我是前端来 点对点二 的消息");
  48.       //2接收消息
  49.       //前端获取的当前登陆的用户userId(和后端一致)
  50.       let userId = '456';
  51.       stompClient4.subscribe('/user/'+userId+'/alone/getResponse2',(response) => {
  52.         this.point2 = response.body
  53.       });
  54.     });
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表