socket通信实现信息同步

场景:

手机端发送消息,在大屏同步展示;

maven依赖

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

1. 后台类结构和代码

 

 socket相关java代码:

package com.xxx.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;


@Component
public class WebSocketConfig {

    /**
     * ServerEndpointExporter 作用
     *
     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

 

package com.xxx.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;


@Component
@RequestMapping(value = "/api/")
public class WebSocketController {

    @Autowired
    private WebSocketServer webSocketServer;

    @GetMapping("/hello/{msg}")
    @ResponseBody
    public String hello(@PathVariable String msg) {
        webSocketServer.sendOneMessage("jiayq", msg);
        return "Hello, World!";
    }

    @PostMapping(value = "/sendMsg")
    @ResponseBody
    public Object chatDB(@RequestParam String params) {
        webSocketServer.sendOneMessage("screen", params);
        return null;
    }

}

 

package com.xxx.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


@Component
@Slf4j
@ServerEndpoint("/api/websocket/{userId}")
public class WebSocketServer {
    private Session session;

    private String userId;

    private static CopyOnWriteArraySet<WebSocketServer> webSockets =new CopyOnWriteArraySet<>();

    private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();

    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId")String userId) {
        try {
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("【websocket消息】有新的连接,总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.userId);
            log.info("【websocket消息】连接断开,总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     * @param
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("【websocket消息】收到客户端消息:"+message);
    }

    /** 发送错误时的处理
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {

        log.error("用户错误,原因:"+error.getMessage());
        error.printStackTrace();
    }


    // 此为广播消息
    public void sendAllMessage(String message) {
        log.info("【websocket消息】广播消息:"+message);
        for(WebSocketServer webSocket : webSockets) {
            try {
                if(webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 此为单点消息
    public void sendOneMessage(String userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null&&session.isOpen()) {
            try {
                log.info("【websocket消息】 单点消息:"+message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 此为单点消息(多人)
    public void sendMoreMessage(String[] userIds, String message) {
        for(String userId:userIds) {
            Session session = sessionPool.get(userId);
            if (session != null&&session.isOpen()) {
                try {
                    log.info("【websocket消息】 单点消息:"+message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2. vue前端代码

发送界面:

<template>
  <div>
    <input type="text" v-model="message" placeholder="输入消息">
    <button @click="sendMessage">发送消息</button>
  </div>
</template>

<script>
import { sendMsg } from '../../api/chat'
export default {
  name: "ChatSocket",
  data () {
    return {
      index: -1,
      reconnectCount: 0,
      message: ""
    }
  },
  created() {
    this.connectWebSocket()
  },
  methods: {
    sendMessage: function() {
      sendMsg({ msg: this.message })
    }
  }
}
</script>

<style scoped>

</style>

 接收界面:

<template>
  <div>
    <div v-for="(item, index) in msg">
      <markdown-it-vue class="md-body" :content="item.msg"/>
    </div>
  </div>
</template>

<script>
import MarkdownItVue from 'markdown-it-vue'
import 'markdown-it-vue/dist/markdown-it-vue.css'

export default {
  name: "ChatSocket",
  data () {
    return {
      index: -1,
      reconnectCount: 0,
      msg: [],
      synth: null,
      speakMsg: ''
    }
  },
  created() {
    this.connectWebSocket()

    this.synth = window.speechSynthesis
    this.speakMsg = new SpeechSynthesisUtterance()

    this.speakMsg.lang = "zh-CN"
    //this.speakMsg.volume = '1';
    //this.speakMsg.rate = 1.5;
    //this.speakMsg.pitch = 1;
  },
  methods: {
    handleStop(){
      this.synth.cancel(this.speakMsg);
    },
    popIframe(){
      alert("触发父界面操作")
    },
    connectWebSocket: function() {
      if('WebSocket' in window){
        this.socket = new WebSocket("ws://127.0.0.1:30316/robot/api/websocket/screen");
      } else{
        alert('Not support websocket')
      }
      //最大尝试链接次数
      const maxReconnectAttempts = 10;
      const reconnectInterval = 1000; // 1秒

      const tryReconnect = () => {
        if (this.reconnectCount < maxReconnectAttempts) {
          console.log('Reconnecting...');
          this.connectWebSocket();
          this.reconnectCount++;
        } else {
          console.log('Exceeded max reconnect attempts, stopping reconnecting.');
        }
      };

      this.socket.addEventListener('open', (event) => {
        console.log('WebSocket 连接已建立')
        let msg = {
          text: "这是发送的txt消息"
        }
        let json = JSON.stringify(msg)
        this.socket.send(json)
      })
      this.socket.addEventListener('message', (event) => {
        //接收到的数据
        const receivedData = event.data;
        let res = JSON.parse(receivedData)
        if(res.msg.trim() == '停止播报'){
          this.handleStop()
          return;
        }

        this.msg.push(res)
        if(res.type == 'answer'){
          this.speakMsg.text = res.msg
          this.synth.speak(this.speakMsg);
        }

        //this.popIframe()
        console.log('Received data:', receivedData)
      })

      // socket.addEventListener('close', (event) => {
      this.socket.addEventListener('close', (event) => {
        console.log('WebSocket connection closed')
        // 在连接关闭时触发重连逻辑
        // setTimeout(() => {
        //   console.log('Reconnecting...')
        //   this.connectWebSocket()
        // }, 1000) // 1秒后重连

        // 清除重连计数,防止无限递增
        // 在连接关闭后,间隔一段时间进行重连
        setTimeout(tryReconnect, reconnectInterval);
      })

      // socket.addEventListener('error', (event) => {
      this.socket.addEventListener('error', (event) => {
        console.error('WebSocket error:', event)
        // 在错误发生时触发重连逻辑
        // setTimeout(() => {
        //   console.log('Reconnecting...')
        //   this.connectWebSocket()
        // }, 1000) // 1秒后重连
        // 在连接错误后,间隔一段时间进行重连
        setTimeout(tryReconnect, reconnectInterval);
      })

      window.addEventListener('beforeunload', (event) => {
        // 当 tab 关闭时,关闭 WebSocket 连接
        this.socket.close();
      });
    }
  },
  components: {
    MarkdownItVue
  }
}
</script>

<style scoped>

</style>

以上实现了socket定点向userId为screen的用户发送消息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

早退的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值