SpringBoot+Vue实现WebSocket

目录

一、WebSocket背景

二、WebSocket实现


一、WebSocket背景

       系统或者平台的一些功能,如聊天功能、消息推送、消息提醒等,需要在不刷新页面的情况下与服务器进行持续同步,达到实时通讯的效果。

实现实时通讯的方案有多种:例如

1、轮询

      客户端定时向服务器发送请求,服务器接到请求后马上返回响应信息并关闭连接。 前端写setTimeOut设置在每隔一段时间不断请求后端,这种方式也能满足需求;但是这样的弊端也很明显,服务器压力加大,再者,当网络不稳定的时候,请求和响应的时间会超出setTimeOut设置的时间,从而出现不同步的情况

2、长轮询

      客户端向服务器发送请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。长轮询同样会给服务器带来很大的压力,而且当连接数达到一定数的时候,服务器可能会出现不再接收的新增连接

WebSocket是实现实时通讯的理想方式。它把客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

二、WebSocket实现

在java中WebSocket有多种实现方式,如

  • 使用@ServerEndpoint注解监听一个WebSocket请求路径;
  • 使用Spring提供的低层级WebSocket API实现

  • 使用STOMP消息实现

本文介绍的是使用@ServerEndpoint注解的实现方式。

添加依赖

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

@ServerEndpoint是webSocket的核心类。首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。

这里主要展示三个类,一个是配置类WebSocketConfig,一个是WebSocketEndPoint,声明方法,另外一个是SessionPool,用来放会话

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
/**
 * @Date 2020/12/13
 * @Author 
 * @Description ServerEndpoint value则是给前端请求websocket的api
 **/
@ServerEndpoint(value = "/api/websocket/{userId}")
@Component
public class WebSocketEndPoint {

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 连接建立成功需要调用的方法
     *
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        // 把会话存入到连接池中
        this.session = session;
        SessionPool.sessionMap.put(userId, session);
    }

    /**
     * 关闭连接
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session) throws IOException {
        SessionPool.close(session.getId());
        session.close();
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message,Session session){
        Map<String,Object> params = JSON.parseObject(message,new HashMap<String,Object>().getClass());
        SessionPool.sendMessage(params);

    }

}
public class SessionPool {

    public static Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    public static void close(String sessionId) throws IOException {
        for (String userId : SessionPool.sessionMap.keySet()) {
            Session session = sessionMap.get(sessionId);
            if (session.getId().equals(sessionId)) {
                sessionMap.remove(userId);
                break;
            }
        }
    }

    public static void sendMessage(String sessionId, String message) {
        sessionMap.get(sessionId).getAsyncRemote().sendText(message);
    }


    public static void sendMessage(String message) {
        for (String sessionId : SessionPool.sessionMap.keySet()) {
            sessionMap.get(sessionId).getAsyncRemote().sendText(message);
        }
    }


    public static void sendMessage(Map<String, Object> params) {
        // 接收消息进行封装,以及写入数据库也在这边实现
        Session session = sessionMap.get(params.get("userId").toString());
        if (session != null) {
            session.getAsyncRemote().sendText(params.get("message").toString());
        }
    }
}

前端代码:

 initWebSocket() {
      const { userId } = this.$store.state.user.userInfo;
      this.userId = userId;
      console.log(this.userId);
      const websocketHeartbeatJs = new WebsocketHeartbeatJs({
        url: `ws://localhost:39888/api/websocket/${userId}`,
        pingTimeout: 15000,
        pongTimeout: 15000,
        reconnectTimeout: 2000,
        pingMsg: "heartBeat",
        repeatLimit: 5
      });
      this.websocket = websocketHeartbeatJs;
      this.websocket.onmessage = this.websocketonmessage;
      this.websocket.onopen = this.websocketonopen;
      this.websocket.onerror = this.websocketonerror;
      this.websocket.onclose = this.websocketclose;
    },
    websocketonopen() {
      if (this.userId !== "1315208483947286528") {
        const message = {
          userId: "1315208483947286528",
          message: "hello123123214"
        };
        this.websocketsend(JSON.stringify(message));
      }
    },
    websocketonerror() {
      // 连接建立失败重连
      this.initWebSocket();
    },
    websocketonmessage(e) {
      // 数据接收
      // const redata = JSON.parse(e.data);
      console.log(e.data, "data");
    },
    websocketsend(Data) {
      // 数据发送
      this.websocket.send(Data);
    },
    websocketclose(e) {
      // 关闭
      console.log("断开连接", e);
    }

由于时间问题,写的比较仓促,后续会补充完善

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

l去留无心

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

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

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

打赏作者

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

抵扣说明:

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

余额充值