vue中使用WebSocket与java SpringBoot进行交互实现聊天室

一、简单介绍下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);
    }
}

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
WebSocket聊天室使用Web技术实现实时双向通信的一种常见方式,结合Spring Boot、Vue.js和MySQL,可以构建一个高性能的后台服务器与前端交互的应用。下面是一个简要的概述: 1. **Spring Boot**: 作为Java的轻量级框架,Spring Boot简化了配置过程,提供了快速启动web应用的能力。你可以利用Spring Websocket来处理WebSocket连接和消息传递。 2. **Vue.js**: 这是一个流行的JavaScript前端框架,用于构建用户界面。在Vue,你可以创建WebSocket的连接,实现实时数据更新和事件驱动的通信。 3. **MySQL**: 作为关系型数据库,MySQL存储聊天室的用户信息、会话记录以及消息内容。通过Ajax或Fetch API,你可以将前端发送的数据保存到MySQL,并在需要时查询更新的数据展示给用户。 **实现步骤:** - **后端(Spring Boot)**: - 创建WebSocket配置,比如`org.springframework.messaging.handler.annotation.MessageMapping`注解处理WebSocket消息。 - 建立数据库模型,如User、Session表,以及Message实体。 - 使用JPA进行数据库操作,实现增删改查。 - **前端(Vue.js)**: - 使用WebSocket库(如`WebSocket`原生API或第三方库`vue-websocket`)建立连接。 - 用户界面设计,包括输入框、聊天列表和发送按钮。 - 实现消息的发送和接收功能,利用Vue的响应式特性实时更新显示。 **相关问题--:** 1. Spring Boot如何启用WebSocket支持? 2. Vue.js如何初始化WebSocket连接并处理接收到的消息? 3. 如何确保Vue前端与Spring Boot后端的数据同步?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

你好!YOYO

你的鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值