当前位置: 首页 > article >正文

springboot集成websokcet+H5开发聊天原型(二)

本文没有写完~~~~

聊天相关数据结构: 

我们初步设计了如下几个数据结构。

//存放 sessionId 与 userId 的map

private Map<String,String> sessionId_userId =new HashMap<>();

// 用于存储用户与群组的关联关系,键为用户ID,值为群组ID列表 一个用户可以加入多个群组 它是一个Map,键是用户ID,值是群组ID列表

private Map<String, List<String>> userGroups = new HashMap<>();

// 用于存储群组信息,键为群组ID,值包含在线用户会话列表和历史消息列表
private Map<String, GroupInfo> groupInfos = new HashMap<>();

用户通过socket和服务端连接的时候,都会传递 
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        LOGGER.info("WebSocket收到的消息: {}", message.getPayload());
        // 将消息反序列化,假设消息是JSON格式,这里解析为Message对象(下面定义)
        Message msg = objectMapper.readValue(message.getPayload().toString(), Message.class);
        String groupId = msg.getGroupId();
        String userId=msg.getUserId();
        int flag=this.checkUserIdAndSessionId(session.getId(),userId);  //检查userId和sessionId是否匹配
        //flag==0 说明userId和sessionId匹配 ,不做更多的操作 直接执行下面的代码
        if(flag==2){   //userId一致 但是 sessionId不一致,说明用户重新建立了session,要把原来该用户相关的session等全部删除掉
              //找到这个用户下原来所有的session,然后全部删除掉
            for (Map.Entry<String, String> entry : sessionId_userId.entrySet()) {
                String storedSessionId = entry.getKey();
                String storedUserId = entry.getValue();
                if (storedUserId.equals(userId)) {
                    sessionId_userId.remove(storedSessionId);
                }
                //by userId remove all the groupInfo
                List<String> groupIds = userGroups.get(userId);
                if (groupIds!= null) {
                    for (String groupId1 : groupIds) {
                        GroupInfo groupInfo = groupInfos.get(groupId1);
                        if (groupInfo!= null) {
                            groupInfo.removeSession(session);
                        }
                    }
                    userGroups.remove(userId);
                }
            }

        }else if(flag==3){  //userId不存在  session不存在 ,用户第一次建立连接
          //do nothing   放在这里就是为了说明flag==3的情况
        }

        if(flag==2 || flag==3){
            sessionId_userId.put(session.getId(),userId);    //sessionId 与 userId 建立映射  是1对1的关系
            List<String> groupIds = userGroups.computeIfAbsent(userId, k -> new ArrayList<>());  // 获取用户的群组ID列表
            groupIds.add(groupId);
        }

        GroupInfo groupInfo = groupInfos.get(groupId);
        if (groupInfo == null) {
            // 如果群组信息不存在,则创建新的群组信息,并添加当前用户的WebSocketSession
            groupInfo = new GroupInfo();
            groupInfo.addSession(session);
            groupInfos.put(groupId, groupInfo);
            // 同时,假设这里从WebSocket连接的属性或者请求参数中获取用户ID(实际需按业务逻辑调整获取方式)
            //String userId = (String) session.getAttributes().get("userId");
//            List<String> groupIds = userGroups.computeIfAbsent(userId, k -> new ArrayList<>());  // 获取用户的群组ID列表
//            groupIds.add(groupId);
        }else {
            groupInfo.addSession(session);  //addSession()方法会检查是否已经存在,如果存在就不会再添加
        }

        // 将消息添加到群组历史消息列表
        groupInfo.addHistoryMessage(msg);

        // 向群组内所有在线用户发送消息
        List<WebSocketSession> sessions = groupInfo.getSessions();
        for (WebSocketSession s : sessions) {
            try {
                s.sendMessage(new TextMessage(objectMapper.writeValueAsString(msg)));
            } catch (IOException e) {
                LOGGER.error("无法发送WebSocket消息", e);
            }
        }
    }


 

uniapp端页面:

<template>
  <view class="chat-room">
    <!-- 聊天记录 -->
    <scroll-view scroll-y="true" class="message-list">
      <view v-for="(message, index) in messages" :key="index" class="message-item">
        <view v-if="message.type === 'text'" class="text-message">
      <!--    <view class="avatar">{{ message.senderAvatar }}</view> -->
          <view class="text">{{ message.content }}</view>
        </view>
        <view v-else-if="message.type === 'image'" class="image-message">
          <image :src="message.content" class="message-image" @click="previewImage(message.content)"></image>
        </view>
      </view>
    </scroll-view>

    <!-- 输入框 -->
    <view class="input-area">
      <input v-model="inputContent" placeholder="输入内容" class="input" />
      <button @click="sendMessage">发送</button>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      messages: [], // 聊天记录
      inputContent: '', // 输入框内容
      socketOpen: false, // WebSocket连接状态
      socket: null, // WebSocket对象
    };
  },
  methods: {
    // 初始化WebSocket连接
    initWebSocket() {
		   uni.setStorageSync('userId',1);  // only test
		   uni.setStorageSync('groupIds',2);  // only test
		    const userId = uni.getStorageSync('userId');
		    const groupIds = uni.getStorageSync('groupIds');
			console.log(groupIds);
		// /wechat/client/chat
      this.socket = uni.connectSocket({
		url: 'ws://127.0.0.1:7877/chat/websocket',
        data: {
            userId: userId,
            groupIds: groupIds
        },
        success: () => {
          console.log('WebSocket连接成功');
          this.socketOpen = true;
        },
        fail: () => {
          console.error('WebSocket连接失败');
        },
      });

      // 监听WebSocket消息
      this.socket.onMessage((res) => {
        const message = JSON.parse(res.data);
        this.messages.push(message); // 将新消息添加到聊天记录中
        this.$forceUpdate(); // 强制更新视图,确保新消息显示
      });

      // 监听WebSocket连接关闭
      this.socket.onClose(() => {
        console.log('WebSocket连接关闭');
        this.socketOpen = false;
      });
    },
    // 发送消息
sendMessage() {
    if (this.inputContent.trim() === '') {
        uni.showToast({
            title: '请输入内容',
            icon: 'none',
        });
        return;
    }

    const message = {
        type: 'text', // 消息类型,可以是text或image,这里发送文字消息示例,发送图片时修改相应字段
        groupId: uni.getStorageSync('groupIds'), // 从本地存储获取当前所在群组ID(需按实际情况调整获取方式)
        sender: uni.getStorageSync('userId'), // 从本地存储获取用户ID(需按实际情况调整获取方式)
        content: this.inputContent
    };

    // 通过WebSocket发送消息(或HTTP请求,根据后端接口决定)
    if (this.socketOpen) {
        this.socket.send({
            data: JSON.stringify(message)
        });
    } else {
		//todo
    }
},
    // 预览图片
    previewImage(url) {
      uni.previewImage({
        current: url, // 当前显示图片的http链接
        urls: [url], // 需要预览的图片http链接列表
      });
    },
  },
  mounted() {
    // 页面加载时初始化WebSocket连接
    this.initWebSocket();

    // 可以从服务器获取历史聊天记录并初始化messages数组(根据需求实现)
  },
};
</script>

<style>
.chat-room {
  padding: 10px;
}

.message-list {
  height: 500px; /* 根据需要调整高度 */
  border-bottom: 1px solid #ccc;
  padding-right: 10px; /* 留出空间给滚动条 */
  overflow-y: auto;
}

.message-item {
  margin-bottom: 10px;
  display: flex;
  align-items: center;
}

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  margin-right: 10px;
}

.text-message .text {
  background-color: #fff;
  padding: 5px 10px;
  border-radius: 5px;
  max-width: 60%; /* 根据需要调整宽度 */
  word-wrap: break-word; /* 防止长文本溢出 */
}

.image-message .message-image {
  width: 100px;
  height: 100px;
  object-fit: cover;
  border-radius: 5px;
}

.input-area {
  display: flex;
  margin-top: 10px;
}

.input {
  flex: 1;
  padding: 5px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

button {
  padding: 5px 10px;
  margin-left: 10px;
  border: none;
  background-color: #1aad19;
  color: #fff;
  border-radius: 5px;
}
</style>

原型效果:

后期再补充~~~~~


http://www.kler.cn/a/469273.html

相关文章:

  • 【FlutterDart】 拖动改变 widget 的窗口尺寸大小GestureDetector~简单实现(10 /100)
  • 利用TCP协议实现客户端—服务器端通信
  • GTX750Ti打DP补丁
  • SQL-leetcode-196. 删除重复的电子邮箱
  • 【服务器项目部署】✈️将本地项目部署到服务器(二)!
  • 【2025最新计算机毕业设计】基于SSM高校校园易换站二手交易平台(高质量源码,可定制,免费部署到本地)
  • UNI-APP弹窗
  • Airflow:HttpSensor实现API驱动数据流程
  • MySQL(三)MySQL DML数据库操作语言
  • Linux硬盘分区 --- gdisk命令GPT分区
  • 基于Springboot的相亲网站系统【附源码】
  • 学习笔记079——数据结构之【树】
  • 开源AI智能名片2+1链动模式S2B2C商城小程序在商业流量获取中的应用研究
  • 【网络协议】IPv4 地址分配 - 第一部分
  • Transformer知识梳理
  • JavaScript 随机 数用法
  • 低空经济来袭,载人无人机研发技术详解
  • c++之左值引用 右值引用 万能引用
  • AI在电子制造中的应用:预测质量控制
  • 深入了解 Python 的 venv 虚拟环境