一、简单介绍下HTML5 WebSocket

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
ok,WebSocket 能实现的通信相关的功能有很多,例如:聊天室,扫码等,这里就是实现的聊天室,下面来看是如何进行交互的!!!(这里默认已经有vue项目基础 && 后端语言为java)

二、前端 VUE: 与WebSocket交互

1.使用样例(无掺杂属于自己的业务)

<template>    
	<div>         
		WebSocket
	</div>    
</template>
<script>
export default {        
	created() { 
		this.initWebSocket(); //进入页面开始初始化websocket建立连接      
	},        
	destroyed() {
		this.websocketclose(); //离开页面断开连接       
	},        
	methods: {            
		initWebSocket() {                
			// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https                
			this.websock = new WebSocket("wss://localhost"); //这里是websocket服务地址,这里的地址可以前端根据后台地址参数规则拼成,也可以向后端请求         
			this.websock.onopen = this.websocketonopen;                
			this.websock.onerror = this.websocketonerror;                
			this.websock.onmessage = this.websocketonmessage;                
			this.websock.onclose = this.websocketclose;              
		},              
		websocketonopen() {                
			console.log("WebSocket连接成功");              
		},              
		websocketonerror(e) {                
			console.log("WebSocket连接发生错误");              
		},              
		websocketonmessage(e) {                
			console.log(e.data);                // console.log(e);              
		},              
		websocketclose(e) {                
			console.log("connection closed (" + e.code + ")");              
		},              
	 }    
}
</script>

2.项目样例(WebSocket实现 聊天室并加入聊天弹幕 功能,弹幕插件使用具体可以 点击查看

 created() {
    this.t = window.setInterval(this.getChatUserList, 5000);
  },
 beforeDestroy() {
   clearInterval(this.t);
 },
 destroyed() {
   this.websocketClose();
 }
 methods: {
    // 初始化 websocket 连接
    initWebSocket() {
      if (typeof WebSocket != "undefined") {
        this.supported = "支持 websocket";
      } else {
        this.supported = "不支持 websocket";
      }
      //ws地址
      var wsAbaseUrl = abaseUrl.substring(abaseUrl.lastIndexOf("/") + 1);
      const wsuri = "wss://" + wsAbaseUrl + "/websocket/" + this.$route.query.liveId + "/" + this.type + "/" + this.userId; 
      this.chatRoomWebsocket = new WebSocket(wsuri);
      this.chatRoomWebsocket.onerror = this.websocketOnError;
      this.chatRoomWebsocket.onmessage = this.websocketOnMessage;
      this.chatRoomWebsocket.onclose = this.websocketOnClose;
    },
    //连接发生错误的回调方法
    websocketOnError() {
      console.log("WebSocket 连接发生错误");
    },
    //接收到消息的回调方法
    websocketOnMessage(event) {
      console.log(event);
      let data = JSON.parse(event.data);
      this.msgHeadImageURL = data.chatImage ? data.chatImage : userPhoto;
      if (data.chatUser != this.userId) {
        this.msgs.push(data);
        this.barrageList.push({
          id: ++this.currentId,
          avatar: this.msgHeadImageURL,
          msg: data.chatContent,
          barrageStyle: "normal",
          time: 5,
          type: 0,
          position: "bottom"
        });
      }
    },
    //连接关闭的回调方法
    websocketOnClose(e) {
      console.log("WebSocket 连接关闭", e);
    },
    //关闭 WebSocket 连接
    websocketClose() {
      this.chatRoomWebsocket.close();
    },
    //发送弹幕+发送消息
    addToList() {
      if (this.sendmsg.split(" ").join("").length != 0) {
        //获取当前时间
        var time = new Date();
        this.sendTime =
          time.getHours() +
          ":" +
          (time.getMinutes() < 10
            ? "0" + time.getMinutes()
            : time.getMinutes());
        let messageData = {
          chatContent: this.sendmsg,
          chatUser: this.userId,
          chatAvatar: this.userInfo.nickName,
          chatImage: this.headImageURL,
          chatTime: this.sendTime
        };
        if (this.chatRoomWebsocket.readyState != "1") {
          // 如果按下按钮时不是连接状态,重连并等到连接成功再发送消息
          this.initWebSocket();
          this.chatRoomWebsocket.onopen = () => {
            this.chatRoomWebsocket.send(JSON.stringify(messageData));
            //发送消息
            this.msgs.push({
              chatContent: this.sendmsg
            });
            //弹幕
            this.msgHeadImageURL = this.headImageURL
              ? this.headImageURL
              : userPhoto;
            this.barrageList.push({
              id: ++this.currentId,
              avatar: this.msgHeadImageURL,
              msg: this.sendmsg,
              barrageStyle: "normal",
              time: 5,
              type: 0,
              position: "bottom"
            });
            this.sendmsg = "";
          };
        } else {
          this.chatRoomWebsocket.send(JSON.stringify(messageData));
          //发送消息
          this.msgs.push({
            chatContent: this.sendmsg
          });
          //弹幕
          this.msgHeadImageURL = this.headImageURL
            ? this.headImageURL
            : userPhoto;
          this.barrageList.push({
            id: ++this.currentId,
            avatar: this.msgHeadImageURL,
            msg: this.sendmsg,
            barrageStyle: "normal",
            time: 5,
            type: 0,
            position: "bottom"
          });
          this.sendmsg = "";
        }
      }
    },
    //定时器获取总人数以及列表
    getChatUserList() {
      let data = {
        sid: this.$route.query.liveId,
        type: 1
      };
      onlineList(data).then(res => {
        if (res.data.state == 200) {
          this.onlineNumber = res.data.data.count;
          this.onlineUserList = res.data.data.userList;
        }
      });
    },
  },

三、后端 java SpringBoot 2.++:相关配置(后端相关配置粘自后端,勿喷~)

1.pom文件中添加

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

2.WebSocket配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
@Configuration
public class WebSocketConfig {
    /**
     * 注入ServerEndpointExporter,
     * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

3.根据业务逻辑WebSocket操作类

package com.library.style.assembly;

import com.alibaba.druid.util.StringUtils;
import com.library.style.model.User;
import com.library.style.repository.UserRepository;
import com.library.style.utils.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

@RestController
@ServerEndpoint(value = "/websocket/{sid}/{type}/{userId}")   //房间号、类型(1,直播聊天)、用户Id、
@Component
public class WebSocket {

    private static WebSocket webSocket;
    private static Logger logger = LoggerFactory.getLogger(WebSocket.class);

    //当前连接数
    private static int onlineCount = 0;

    //存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>();

    //与某个客户端的连接会话
    private Session session;

    //客户端唯一标识sid(直播ID)
    private String sid = "";
    //用户类型
    private Integer type=0;
    //用户ID
    private Integer userId = 0;
    //用户昵称
    private String nickName="";
    //用户头像地址
    private String headImageUrl="";
    @Autowired
    private  UserRepository userRepository;

    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    @PostConstruct
    public void init() {
        webSocket = this;
        webSocket.userRepository = this.userRepository;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid,  @PathParam("type") Integer type,@PathParam("userId") Integer userId) {
        moreWindow(sid,userId,type);
        //在线数加1
        addOnlineCount();
        this.session = session;
        //加入set中
        webSocketSet.add(this);
        this.sid = sid;
        this.userId = userId;
        this.type=type;
        User user=WebSocket.webSocket.userRepository.findById(userId).get();
        this.nickName=user.getNickName();
        this.headImageUrl=user.getHeadImageURL();
        logger.info("用户ID:"+userId+"用户昵称:"+nickName+"新连接:sid=" + sid + " 当前在线人数" + getOnlineCount());
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            logger.error("websocket IO异常");
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        //群发消息
        for (WebSocket item : webSocketSet) {
            try {
                if(item.sid.equals(this.sid)){
                    item.sendMessage(message);
                    System.out.println("--------------------"+message+"总人数"+onlineCount);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 同一用户打开多个窗口问题
     *
     * @param sid
     */
    public void moreWindow(String sid,Integer userId,Integer type) {
        if (StringUtils.isEmpty(sid)) {
            return;
        }
        if(webSocketSet.isEmpty()){
            return;
        }
        for (WebSocket item : webSocketSet) {
            if (item.sid.equals(sid)&&item.userId.equals(userId)&&item.type==type) {
                //已经有相同的了
                webSocketSet.remove(item);
                subOnlineCount();
            }
        }
    }

    /**
     * 发送消息给指定用户
     *
     * @param message
     * @param sid
     */
    public static void sendMessage(String message, @PathParam("sid") String sid) {
        logger.info("发送消息:sid=" + sid + " message:" + message);
        for (WebSocket item : webSocketSet) {
            try {
                if (sid == null) {
                    item.sendMessage(message);
                    System.out.println("+++++++++++++++"+message);
                } else if (item.sid.equals(sid)) {
                    logger.info("开始发送消息:sid=" + sid);
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                logger.error("发送消息失败 sid:"+sid,e);
                continue;
            }
        }
    }

    @OnClose
    public void onClose() {
        logger.info("连接关闭:sid=" + sid + " 当前在线人数" + getOnlineCount());
        webSocketSet.remove(this);
        subOnlineCount();
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 当前在线人数
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 添加在线人数
     */
    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    /**
     * 减少在线人数
     */
    public static synchronized void subOnlineCount() {
        if (WebSocket.onlineCount <= 0) {
            WebSocket.onlineCount = 0;
            return;
        }
        WebSocket.onlineCount--;
    }

    /**
     * 人数列表
     */
    @PostMapping(value = "/numberList")
    public  JsonResult numberList(@RequestParam(value = "sid") String sid,@RequestParam(value = "type") Integer type){
        Map map=new HashMap<>();
        List<User> userList=new ArrayList<>();
        Integer count=0;
        for (WebSocket item : webSocketSet) {
            if(item.sid!=null&&item.sid.equals(sid)&&item.type==type){
                User user=new User();
                user.setNickName(item.nickName);
                user.setUserId(item.userId);
                user.setHeadImageURL(item.headImageUrl);
                userList.add(user);
                count++;
            }
        }
        map.put("userList",userList);
        map.put("count",count);
        return new JsonResult(map);
    }
}

Logo

前往低代码交流专区

更多推荐