朋友圈与聊天功能模块
创建于 2025 年 12 月 28 日
项目介绍
本项目是在若依 RuoYi 3.9.0 后端(ruoyi-admin / ruoyi-system / ruoyi-common 等标准多模块)之上二次开发的移动端社交功能模块,前端为独立的 uni-app 工程(前端/ 目录,Vue 2.6.11 + @dcloudio/uni-app),一套代码可打包 H5、Android/iOS App 与微信小程序。仓库不依赖 README,核心资产直接体现在代码与 SQL 中:后端/sql/ 提供 chat_conversations、chat_messages 业务表及对应的管理端菜单脚本(conversationsMenu.sql、messagesMenu.sql),朋友圈三张表(sys_moments、sys_moments_comment、sys_moments_like)与激活码、反馈表则由若依代码生成器生成领域对象后手工扩展;测试/ 目录内置三个 WebSocket 调试 HTML 页面;参考项目/ 保留着接入调研的 netty-websocket-spring-boot-starter、网易云信 NERTC 接入文档等资料,能清楚看到”先 WebSocket 信令、后 NERTC 音视频”的演进轨迹。
项目定位是一个面向移动端用户的社交闭环:手机号验证码登录(互亿无线短信服务)→ 激活码绑定角色 → 在朋友圈发布图文/视频动态、点赞、二级评论 → 通过会话列表与在线好友实时聊天、发起语音通话,同时提供”我的点赞""用户主页""问题反馈”等个人中心页面;管理端(若依后台)则对朋友圈动态、评论、点赞、会话、消息提供标准 CRUD、Excel 导出与按钮级权限控制。
项目架构
整体为”若依单体后端 + uni-app 移动端”的前后端分离结构,实时通信由独立 WebSocket 端口承担:
| 层 | 技术栈 | 说明 |
|---|---|---|
ruoyi-admin | Spring Boot 2.5.15、Java 8、MyBatis、PageHelper、fastjson2 | 移动端 API 控制器:ApiChatController(会话/消息 HTTP 兜底)、ApiChatWebSocket(实时端点)、ApiNertcController(NERTC Token)、ApiUserController(资料/头像)、ApiActivationController(激活码);管理端 SysMomentsController / SysMomentsCommentController / SysMomentsLikeController 等 |
| 实时层 | org.yeauty:netty-websocket-spring-boot-starter:0.12.0 | @ServerEndpoint(path = "/ws/chat/{userId}", port = "${websocket.port:19730}"),@BeforeHandshake 校验用户、@OnOpen/@OnMessage/@OnClose/@OnError 生命周期,ConcurrentHashMap<Long, Session> 维护在线表 |
ruoyi-system | MyBatis XML | 新增 SysMoments / SysMomentsComment / SysMomentsLike / ChatConversations / ChatMessages / SysActivationCode / SysFeedback 等 domain-mapper-service 三层,朋友圈列表 SQL 手写联查 |
前端 前端/ | uni-app(Vue 2.6.11) | pages/moments/(时间流、发布、评论、用户主页、管理)、pages/chat/(会话列表、聊天详情)、pages/my/、pages/login/;utils/api.js 自带兼容安卓原生环境的 URLSearchParams 实现与按环境切换的 baseUrl;utils/websocket.js 封装 WebSocketManager(30s 心跳、最多 5 次 3s 间隔重连、消息处理器注册制) |
数据库 后端/sql/ | MySQL 5.7(utf8mb4) | chat_conversations(会话:user_id / other_user_id / last_message / last_message_time / unread_count / del_flag,外键级联 sys_user)、chat_messages(消息:conversation_id / sender_id / receiver_id / content / msg_type 0文本 1图片 2语音 3视频 / is_read / status 可撤回)、sys_moments(content / image_urls 逗号分隔 / video_url / like_count / comment_count / status)、sys_moments_comment(parent_id / reply_user_id / reply_comment_id 支持二级回复)、sys_moments_like(moments_id + user_id) |
后端分层严格遵循若依规范:管理端控制器全部带 @PreAuthorize("@ss.hasPermi('system:moments:list')") 类权限注解与 @Log 操作日志,移动端接口复用 BaseController 的 getUserId() 走 JWT 登录态;朋友圈与点赞等接口由前端直接调用 /system/moments、/system/like、/system/comment 等管理端路由(统一由若依 Token 鉴权),聊天则走独立的 /api/chat/* 移动端路由与 /ws/chat/{userId} 实时通道,实现”HTTP 兜底 + WS 实时”双通道。
核心功能
朋友圈时间流与发布。 pages/moments/moments.vue 使用 uni_modules 的 qizai9527-dynamic 动态卡片组件渲染九宫格图文流,发布页 publish.vue 支持 500 字文字、最多 9 张图片或单个视频(image_urls 逗号分隔、video_url 独立字段,图片/视频二选一),支持编辑模式回填并提交 /system/moments。列表接口 selectSysMomentsListWithLikeStatus 的 Mapper 一次联查完成三件事:left join sys_user 用 COALESCE(u.nick_name, u.user_name) 取昵称、带出头像;left join sys_moments_like l on m.id = l.moments_id and l.user_id = #{currentUserId} 用 case when l.id is not null then true else false end 计算当前用户是否已赞;order by m.create_time desc 配合 PageHelper 分页。页面在 onShow 时重置到第一页刷新,保证”发布完回来立刻看到新动态”,App 端用原生悬浮按钮实现”+“发布入口。
点赞与二级评论。 点赞独立存 sys_moments_like(支持按 moments_id + user_id 精确取消),计数走 incrementLikeCount / decrementLikeCount 两条 SQL,减少时用 case when ifnull(like_count, 0) > 0 then ... else 0 end 防止负数;评论表 sys_moments_comment 除 parent_id 外还设计了 reply_user_id(回复给谁)与 reply_comment_id(回复哪条评论,由 sql/abc.sql 的 ALTER TABLE 增量脚本补充),配合评论组件 comment-node 递归渲染实现”楼中楼”。增删评论时后端调用 updateCommentCount 用 select count(*) 子查询重算动态的评论数,保证计数永远与实际一致;“我的点赞”(getLikedMoments)用 inner join sys_moments_like 按点赞时间倒序反查动态列表。
WebSocket 实时聊天。 ApiChatWebSocket 是聊天的心脏:@BeforeHandshake 先查 sys_user 验证用户存在才放行;onMessage 按 type 分发 chat(聊天消息)、history(分页历史)、heartbeat(心跳,前端每 30s 一次)、read_receipt(已读回执,校验”只有接收者本人才能发”)、voice_data(语音数据转发,10s 汇总一次日志防刷屏)、voice_call_request/accept/reject/end(通话信令)。聊天消息会先写库(chat_messages,未读 is_read=0)再实时推送:接收者在线则直接送达并顺手把消息标记已读、未读计数减一;离线则消息落库、会话 unread_count 加一,等对方上线后由会话列表展示未读角标。每次收发都会给双方推送 conversation_update 或 confirm 消息,让会话列表的”最后一条消息 + 时间”实时更新;online_users / user_status 消息让新连接用户拿到在线列表、其余用户收到上下线广播。HTTP 侧的 ApiChatController(/api/chat/messages、/api/chat/conversations 等)实现相同逻辑作为兜底,并处理”删除会话后重建时把旧消息 conversationId 迁移到新会话”这类边界情况。
双向会话与未读计数。 会话采用”一人一条”的双向设计:A 与 B 聊天时系统为 A、B 各建一条 chat_conversations 记录(user_id 指向本人、other_user_id 指向对方),删除会话只逻辑删除自己的那一条(del_flag='2'),互不影响;getMessages 会合并两个方向、按 sender_id/receiver_id 聚合消息并按时间倒序取最近 50 条后反转,再清空本人会话的未读数。列表接口按 last_message_time 倒序排序并回填对方昵称/头像,未读数超过 99 显示为”99+”。
语音通话与配套能力。 聊天详情页 chat-detail.vue 内置 nertc-voice-call 语音通话组件(App 端使用,组件注释里保留了可切回纯 WebSocket 语音方案的说明):通话信令先经 WebSocket 协商(voice_call_request → accept / reject → end,接听时由服务端生成统一的 callStartTime 时间戳分发给双方),媒体流走网易云信 NERTC,ApiNertcController 用 sha1(appSecret + uid + curTime + ttl + channelName) 生成有效期 24 小时的 Base64 Token。除此之外,项目还集成了手机号+短信验证码登录(互亿无线)、激活码绑定角色(sys_activation_code / sys_user_activation_code,管理员生成/历史/删除)、头像上传压缩(ImageCompressUtils 基于 Thumbnailator:超过 500KB 的图片压缩到最大 800×800、JPEG 质量 0.8)与问题反馈(SysFeedback)等完整外围能力。
功能截图
暂无运行截图。
快速上手
-
准备数据库:在 MySQL 5.7 中先执行
后端/sql/ry_20250522.sql(若依框架基础库),再执行conversations.sql、messages.sql建聊天表,执行conversationsMenu.sql、messagesMenu.sql挂管理端菜单;朋友圈三表与abc.sql增量脚本(补reply_comment_id、video_url字段)来自业务库导出,需按实际库结构合并执行。 -
启动后端:修改
ruoyi-admin/src/main/resources/application-druid.yml的数据源配置与application.yml中的短信、NERTC 密钥后运行:
cd 后端 && mvn clean package -DskipTests
java -jar ruoyi-admin/target/ruoyi-admin.jar
- 启动移动端:
前端/为 uni-app 工程(HBuilderX 或 CLI 均可),先确认utils/api.js中baseUrl指向后端地址,再运行 H5 版或打包 App/小程序:
cd 前端 && npm install && npm run dev:h5
- 联调实时通道:WebSocket 独立监听端口
19730(websocket.port可配),需保证该端口可访问;测试/websocket-debug.html、websocket-detailed-debug.html可直接在浏览器打开,用于观察握手、在线用户、消息收发与信令流转,方便先于 App 端排查实时链路。
总结
这个项目是”若依脚手架 + 真实社交业务”结合的典型样本,值得借鉴的点有三处:一是朋友圈列表的 SQL 设计——用一次 left join 同时解决昵称头像联查与”当前用户是否已赞”(is_like 布尔字段),点赞/评论计数用增减 SQL 与子查询重算双保险,评论表通过 parent_id + reply_user_id + reply_comment_id 三字段支撑楼中楼回复,这些都是在若依代码生成器产物上手工打磨 Mapper 的成熟套路;二是聊天双通道架构——WebSocket 负责实时性(心跳、已读回执、在线广播、会话列表增量更新),HTTP 接口负责兜底与重放,消息一律先落库再推送,离线消息靠 unread_count 角标承接,并用”在线即读”策略让未读数天然准确;三是语音能力的演进路径——先用自己的 WebSocket 信令 + 语音数据转发跑通流程(voice_data 消息与 10 秒日志汇总),再无缝升级到网易云信 NERTC 音视频,服务端只多一个 Token 生成接口,组件层保留两套实现的切换开关。对想在若依上快速搭建移动端社交/IM 类功能、或研究 WebSocket 信令设计的开发者,这份代码是很好的落地参考。