自己实现一个聊天模块

1,825 阅读3分钟

大致的实现效果

image.png 群聊和私聊 image.png 联系人 image.png

这个是我独立写完的一个模块,以前并没有怎么了解websocket,很长一段时间都是使用轮询完成类似的功能,了解到这个之后,我就很快更换了技术栈
后端我使用的是go语言

// 升级HTTP连接为WebSocket
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
//从gin哪里拿到writer和request这两个东西
if err != nil {
    fmt.Printf("WebSocket升级失败: %v\n", err)
    c.AbortWithStatus(http.StatusInternalServerError)
    return
    //这个地方是对前端发生意外关闭的处理
}
log.Printf("websocket心跳开始")
// 注册新客户端(加锁保证线程安全)
clientsMu.Lock()
clients[ws] = " "
clientsMu.Unlock()

先是自己初始化了一个链接,然后处理了一下链接的客户端,在之后的代码,我就是对clients[ws]进行处理,令他们等于我的身份id,这些id储存在我的mysql数据库里面
我根据发送过来的消息区分群组消息和私聊消息,把私聊消息丢到另外一个函数里面处理(判断对方是否在线,是否需要发送历史消息,是否储存历史消息),把群组消息进行保存,并且广播出去

前端是vue3+element-plus+pinia

  state: () => ({
    ws: null,
    dataCon: [],
    dataMy: [],
    //这些都是群组桶
    //私聊桶
    privateCon: [],
    privateMy: [],
    jwt: localStorage.getItem('jwt') || '',
    setTime: null,
  }),

使用了一个很笨的方法,根据是否带有目标用户把消息分为群组和私聊消息,再根据用户id决定这条消息是我发送的还是对方发送的,再进行分类,用户id会在每次页面更新的时候和jwt一起发向后端进行校验 但是,我这样的分类方法,也导致我需要通过时间对消息进行区分

function timeToSeconds(timeStr) {
  // 检查是否是日期时间格式(含 '/' 和空格)
  if (/\d{4}\/\d{1,2}\/\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}/.test(timeStr)) {
    // 解析日期时间部分
    const [datePart, timePart] = timeStr.split(' ');
    const [year, month, day] = datePart.split('/').map(Number);
    const [hour, minute, second] = timePart.split(':').map(Number);

    // 创建 Date 对象(UTC 时间)
    const date = new Date(Date.UTC(year, month - 1, day, hour, minute, second));

    // 返回 UNIX 时间戳(秒)
    return Math.floor(date.getTime() / 1000);
  } else {
    // 处理持续时间格式(原逻辑)
    const [dayPart, timePart = ''] = timeStr.split('d');
    let days = 0;
    let remainingTime = timeStr;

    // 提取天数
    if (timePart) {
      days = parseInt(dayPart, 10) || 0;
      remainingTime = timePart;
    }

    // 提取小时、分钟、秒
    const timeComponents = remainingTime.split(':').map(Number);
    const h = timeComponents[0] || 0;
    const m = timeComponents[1] || 0;
    const s = timeComponents[2] || 0;

    // 计算总秒数
    return days * 86400 + h * 3600 + m * 60 + s;
  }
}

通过我的最初想法加ai的修改,最终完成了一个通过时间对消息进行区分的方法 将私聊或者群聊的所有信息混合一起,通过sort对这个数组进行排序,然后传给组件,完成在页面的渲染

写到这里,大概上边就是我自己思考的结果了,没有参考现成的例子,自己思考再写出来的,遇到了很多错误,轻喷hh,只是在自己写一个完整的项目的过程,go才学了两个月,很多不会的地方,刚刚开始这个项目的时候,还在纠结微服务还是单体应用,后来发现,微服务框架我根本看不懂,笑死
vue3也是,发现他的很多api都有意想不到的效果,真是牛逼

这只是一个分享 这只是一个分享,愿你开心