【VUE小型网站开发】socket.io聊天室

本功能参考SpringBoot 整合 Socket 实战案例

1. 基本功能搭建

1.1 引入依赖

xml 复制代码
        <!-- Socket.io -->
        <dependency>
            <groupId>com.corundumstudio.socketio</groupId>
            <artifactId>netty-socketio</artifactId>
            <version>1.7.7</version>
        </dependency>

1.2 添加yml配置

根据需求进行调整

yaml 复制代码
socketio:
  #  SocketIO服务器的host
  host: localhost
  #  SocketIO服务器的端口
  port: 8503
  #  SocketIO服务器允许的最大帧负载长度
  maxFramePayloadLength: 1048576
  #  SocketIO服务器的最大http内容长度
  maxHttpContentLength: 1048576
  #  SocketIO服务器的线程数量
  bossCount: 1
  #  SocketIO服务器的工作线程数量
  workCount: 100
  #  SocketIO服务器的允许自定义请求
  allowCustomRequests: true
  #  SocketIO服务器的升级超时时间
  upgradeTimeout: 10000
  #  SocketIO服务器的ping超时时间
  pingTimeout: 60000
  #  SocketIO服务器的ping间隔时间
  pingInterval: 25000

1.3 创建配置类

java 复制代码
package com.tool.tooladmin.webSocket.config;

import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author yhc
 * @description SocketServerConfig
 */
@Configuration
public class SocketServerConfig {
    /**
     * SocketIO服务器的host
     */
    @Value("${socketio.host}")
    private String host;
    /**
     * SocketIO服务器的端口
     */
    @Value("${socketio.port}")
    private Integer port;
    /**
     * SocketIO服务器的boss线程数
     */
    @Value("${socketio.bossCount}")
    private int bossCount;
    /**
     * SocketIO服务器的work线程数
     */
    @Value("${socketio.workCount}")
    private int workCount;
    /**
     * 是否允许自定义请求
     */
    @Value("${socketio.allowCustomRequests}")
    private boolean allowCustomRequests;
    /**
     * SocketIO服务器的升级超时时间
     */
    @Value("${socketio.upgradeTimeout}")
    private int upgradeTimeout;
    /**
     * SocketIO服务器的ping超时时间
     */
    @Value("${socketio.pingTimeout}")
    private int pingTimeout;
    /**
     * SocketIO服务器的ping间隔时间
     */
    @Value("${socketio.pingInterval}")
    private int pingInterval;

    /**
     * 创建一个SocketIOServer实例,并设置相关配置。
     */
    @Bean
    public SocketIOServer socketIOServer() {
        SocketConfig socketConfig = new SocketConfig();
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        buildSocketConfig(socketConfig, config);
        return new SocketIOServer(config);
    }

    /**
     * 创建一个SpringAnnotationScanner实例,用于扫描netty-socketIo的注解( @OnConnect、@OnEvent等)
     */
    @Bean
    public SpringAnnotationScanner springAnnotationScanner() {
        return new SpringAnnotationScanner(socketIOServer());
    }

    /**
     * 设置SocketIO服务器的配置,将SocketConfig配置项设置到com.corundumstudio.socketio.Configuration中
     * @param socketConfig
     * @param config
     */
    private void buildSocketConfig(SocketConfig socketConfig, com.corundumstudio.socketio.Configuration config) {
        config.setSocketConfig(socketConfig);
        config.setHostname(host);
        config.setPort(port);
        config.setBossThreads(bossCount);
        config.setWorkerThreads(workCount);
        config.setAllowCustomRequests(allowCustomRequests);
        config.setUpgradeTimeout(upgradeTimeout);
        config.setPingTimeout(pingTimeout);
        config.setPingInterval(pingInterval);
    }
}

1.4 创建消息实体类

java 复制代码
package com.tool.tooladmin.webSocket.domain;

import lombok.Data;

@Data
public class SocketMessageVo {
    /** 消息类型 */
    private String type;
    /** 消息内容 */
    private String content;
    /** 消息发送者 */
    private String from;
    /** 消息接收者 */
    private String to;
    /** 消息通道 */
    private String channel;
}

1.5 封装socket常用函数

java 复制代码
package com.tool.tooladmin.webSocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
public class SocketUtil {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    //暂且把用户&客户端信息存在缓存
    public static ConcurrentMap<String, SocketIOClient> connectMap = new ConcurrentHashMap<>();

    @OnEvent(value = "CHANNEL_SYSTEM")
    public void systemDataListener(String receiveMsg) {
        if (!StringUtils.hasLength(receiveMsg)){
            return;
        }
        JSONObject msgObject = (JSONObject) JSON.parse(receiveMsg);
        String userFlag = String.valueOf(msgObject.get("from"));
        String content = String.valueOf(msgObject.get("content"));
        log.info("收到用户 : {} 推送到系统频道的一条消息 :{}",userFlag,content );
    }

    public void sendToAll(Map<String, Object> msg,String sendChannel) {
        if (connectMap.isEmpty()){
            return;
        }
        //给在这个频道的每个客户端发消息
        for (Map.Entry<String, SocketIOClient> entry : connectMap.entrySet()) {
            entry.getValue().sendEvent(sendChannel, msg);
        }
    }

    public void sendToOne(String userFlag, Map<String, Object> msg,String sendChannel) {
        //拿出某个客户端信息
        SocketIOClient socketClient = getSocketClient(userFlag);
        if (Objects.nonNull(socketClient) ){
            //单独给他发消息
            socketClient.sendEvent(sendChannel,msg);
        }
    }

    /***
     * 广播在线用户数
     */
    @OnEvent(value = "onlineUsers")
    public void broadcastOnlineUsers() {
        int count = connectMap.size();
        System.out.println("当前在线用户数:" + count);
        if (!connectMap.isEmpty()){
            for (Map.Entry<String, SocketIOClient> entry : connectMap.entrySet()) {
                entry.getValue().sendEvent("onlineUsers", count);
                System.out.println("已向用户:" + entry.getKey() + " 发送在线用户数:" + count);
            }
        }
    }


    /**
     * 识别出客户端
     * @param userFlag
     * @return
     */
    public SocketIOClient getSocketClient(String userFlag){
        SocketIOClient client = null;
        if (StringUtils.hasLength(userFlag) &&  !connectMap.isEmpty()){
            for (String key : connectMap.keySet()) {
                if (userFlag.equals(key)){
                    client = connectMap.get(key);
                }
            }
        }
        return client;
    }
}

1.6 创建 socket handler

负责客户端的连接、断开等

java 复制代码
package com.tool.tooladmin.webSocket;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SocketHandler {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SocketIOServer socketIoServer;
    @PostConstruct
    private void start(){
        try {
            socketIoServer.start();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @PreDestroy
    private void destroy(){
        try {
            socketIoServer.stop();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @OnConnect
    public void connect(SocketIOClient client) {
        String userFlag = client.getHandshakeData().getSingleUrlParam("userFlag");
        SocketUtil.connectMap.put(userFlag, client);
        log.info("客户端: "+ userFlag+ "已连接");
    }
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String userFlag = client.getHandshakeData().getSingleUrlParam("userFlag");
        log.info("客户端:" + userFlag + "断开连接");
        SocketUtil.connectMap.remove(userFlag, client);
    }
}

1.7 创建前端VUE页面

发现使用VUE一直掉线和存在无法使用,可能是用法不对,使用html倒是正常,未发现问题点,等发现后再调整代码

html 复制代码
<template>
  <h1>聊天室</h1>
  <h5>当前在线用户: {{ onlineUsers }}</h5>
  <div>
    <ul>
      <li v-for="msg in messages" :key="msg">{{ msg }}</li>
    </ul>
  </div>
  <input v-model="newMessage" @keyup.enter="sendMessage" placeholder="输入消息...">
  <button @click="sendMessage">发送</button>
</template>

<script setup>
import {ref, onMounted, onUnmounted} from 'vue';
import {io} from 'socket.io-client';

const newMessage = ref('');
const messages = ref([]);
const onlineUsers = ref(0);

let socket = null;

onMounted(() => {
  // 替换为你的 Socket.IO 服务器地址
  const userFlag = 'userFlag=用户' + Math.floor(Math.random() * 1000);
  socket = io('http://localhost:8889', {
    // transports: ['websocket'], // 指定传输方式,如WebSocket
    autoConnect: true, // 是否自动连接
    reconnection: true, // 是否自动重新连接
    // reconnectionAttempts: 3, // 重新连接尝试次数
    // reconnectionDelay: 1000, // 重新连接延迟时间(毫秒)
    query: { userFlag: userFlag }, // 自定义查询参数
  });

  socket.on('connect', () => {
    console.log('已连接到聊天室');
  });

  socket.on('message', (data) => {
    console.log('222222');
    messages.value.push(data);
  });

  socket.on('disconnect', () => {
    console.log('已断开连接');
  });

  socket.on('error', (error) => {
    console.error('Socket.IO 错误:', error);
  });

  socket.on('onlineUsers', (count) => {
    console.log('当前在线用户:', count)
    onlineUsers.value = count;
  });

});

onUnmounted(() => {
  if (socket) {
    socket.disconnect();
  }
});

const  sendMessage = () =>  {
  console.log('发送消息', newMessage.value)
  if (newMessage.value.trim()) {
    socket.emit('CHANNEL_SYSTEM', JSON.stringify({
      'content': newMessage.value,
      'from': 'user_JC'
    }));
    newMessage.value = '';
  }
}
</script>

<style scoped>
/* 添加样式以美化聊天界面 */
</style>
相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax