{"id":20986628,"url":"https://github.com/dpwgc/fast-im","last_synced_at":"2026-03-02T20:36:20.721Z","repository":{"id":53570006,"uuid":"474914906","full_name":"dpwgc/fast-im","owner":"dpwgc","description":"FastIM 一个基于Spring Boot + WebSocket + Redis，可快速开发的分布式即时通讯群聊系统。适用于直播间聊天、游戏内聊天、客服聊天等临时性群聊场景。","archived":false,"fork":false,"pushed_at":"2022-04-25T06:19:52.000Z","size":585,"stargazers_count":34,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-31T02:44:26.736Z","etag":null,"topics":["im","java","nosql","redis","server","spring-boot","web","websocket"],"latest_commit_sha":null,"homepage":"https://gitee.com/dpwgc/fast-im","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dpwgc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-28T08:37:00.000Z","updated_at":"2025-05-02T05:45:51.000Z","dependencies_parsed_at":"2022-09-09T07:10:09.903Z","dependency_job_id":null,"html_url":"https://github.com/dpwgc/fast-im","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dpwgc/fast-im","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Ffast-im","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Ffast-im/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Ffast-im/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Ffast-im/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpwgc","download_url":"https://codeload.github.com/dpwgc/fast-im/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Ffast-im/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30018584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T17:00:27.440Z","status":"ssl_error","status_checked_at":"2026-03-02T17:00:03.402Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["im","java","nosql","redis","server","spring-boot","web","websocket"],"created_at":"2024-11-19T06:14:23.567Z","updated_at":"2026-03-02T20:36:20.688Z","avatar_url":"https://github.com/dpwgc.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fast-IM\n\n## 基于Spring Boot + WebSocket + Redis的分布式即时通讯群聊系统\n\n#### 适用于直播间聊天、游戏内聊天、客服聊天等临时性群聊场景。\n\n* 使用WebSocet连接IM服务端与客户端。\n* 使用Redis string存储用户登录令牌，key为\"login:\"+用户id，value为token。\n* 使用Redis list存储群聊消息，key为 \"gml:\"+群组id，value为群组消息列表（JSON格式）。\n* 使用Redis set存储用户加入的群组列表，key为 \"ugs:\"+用户id，value为用户当前加入的所有群组id集合。\n* 使用Redis pub/sub订阅发布功能实现分布式WebSocket推送服务，订阅发布主题管道名称为 \"mq:\"+群组id（每个群组单独共享一个主题）。\n\n![avatar](./ws_img.jpg)\n***\n\n## 实现功能\n* 分布式WebSocket推送服务，客户端向任意一个IM服务端发送消息，其他IM服务端都可接收到这条消息，并将消息推送给所有在线连接的同群组客户端（基于Redis订阅/发布功能及WebSocket连接实现）。\n* 临时群聊快速搭建（适用于直播间聊天、游戏内聊天）。\n* 群聊历史聊天记录查询（HTTP接口实现）。\n* 自动清除长期废弃的群聊（基于Redis键值过期功能）。\n* 实时推送用户所加入的群组列表的最新动态（WebSocket连接实现）。\n* 用户登录状态验证（Redis Token）。\n* 一定时间内的消息撤回功能（HTTP接口实现）。\n\n***\n\n## 使用说明\n* 部署Redis。\n* 配置application.yml文件中的参数。\n* 启动项目。\n* 启动后访问 http://127.0.0.1:9000/test/websocket ，测试WebSocket连接。\n\n![avatar](./ws_test.jpg)\n***\n\n## 自定义业务逻辑\n* 可在controller/UserController及service/UserService文件中自定义用户登录逻辑。\n* 可在config/InterceptorConfig及interceptor/ApiInterceptor文件中自定义http接口拦截器及拦截路由。\n\n***\n\n## 消息模板说明\n```\ngroupId:消息所属群组id\nuserId:发送该条消息的用户id\ninfo:消息主体内容\nts:消息创建时间戳（毫秒级）\n```\n为了省内存，没有消息唯一id/uuid，查询某条消息时，按照groupId、userId、ts这三个字段来匹配消息。先根据groupId查找到指定Redis list，再根据userId和ts查找到list中的指定消息（ps：即使有人在同一毫秒内向某群组插入了两条消息，也无大碍，只会略微影响消息撤回功能及获取历史消息记录功能）。\n***\n\n## WebSocket连接说明\n\n### 群组聊天室连接（监听群内聊天消息更新）\n\u003ews://127.0.0.1:9000/group/chat/{groupId}/{userId}/{token}\n* `groupId:群组id`\n* `userId:用户id`\n* `token:登录令牌，默认不开启websocket令牌验证，可随意填写一串字符（不能为空）`\n\n连接建立后服务端将返回该群组最新的一批消息列表list与该群组消息总数total（以JSON字符串形式推送），格式如下：\n```json\n{\n  \"list\":[\n    {\"groupId\":\"1\",\"userId\":\"3\",\"info\":\"1-hello\",\"ts\":1648368380132}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"2-hello\",\"ts\":1648368386964}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"3-hello\",\"ts\":1648368388389}, \n    {\"groupId\":\"1\",\"userId\":\"3\",\"info\":\"4-hello\",\"ts\":1648368390249}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"5-hello\",\"ts\":1648368391742}, \n    {\"groupId\":\"1\",\"userId\":\"2\",\"info\":\"6-hello\",\"ts\":1648368393362}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"7-hello\",\"ts\":1648368394696}, \n    {\"groupId\":\"1\",\"userId\":\"6\",\"info\":\"8-hello\",\"ts\":1648368396091}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"9-hello\",\"ts\":1648368397434}, \n    {\"groupId\":\"1\",\"userId\":\"1\",\"info\":\"0-hello\",\"ts\":1648368400179}\n  ], \n  \"total\":399\n}\n```\n* `groupId:该消息所属群组id`\n* `userId:发送该消息的用户id`\n* `info:消息主体信息`\n* `ts:消息创建时间戳（毫秒级）`\n\n注：如果开启了websocket令牌验证，且用户登录令牌token验证失败，则服务端返回\"440\"代码，并断开连接。\n```json\n\"440\"\n```\n\n连接成功后客户端即可向服务端发送消息\n\n* 客户端发送\n```json\n\"im hello\"\n```\n\n然后服务端向所有在线的群组成员推送该条消息（以JSON字符串形式推送），格式如下：\n```json\n{\n  \"groupId\":\"1\",\n  \"userId\":1,\n  \"info\":\"im hello\",\n  \"ts\":1648380678385\n}\n```\n\n### 首页群组列表连接（监听用户加入的所有群组数据更新）\n\u003ews://127.0.0.1:9000/group/list/{userId}/{token}\n* `userId:用户id`\n* `token:登录令牌，默认不开启websocket令牌验证，可随意填写一串字符（不能为空）`\n\n连接建立后，服务端将周期性检查用户群组列表中是否有新消息到达，如果有新消息到达，则向客户端发送最新的群组信息列表（以JSON字符串形式推送），推送数据格式如下：\n```json\n[\n  {\n    \"newMessage\":\n      {\n        \"groupId\":\"1\",\n        \"userId\":\"2\",\n        \"info\":\"hi\",\n        \"ts\":1648380678385\n      }, \n    \"total\":1\n  }, \n  {\n    \"newMessage\":\n      {\n        \"groupId\":\"1\",\n        \"userId\":\"1\",\n        \"info\":\"hello\",\n        \"ts\":1648380642476\n      },\n    \"total\":17\n  }\n]\n```\n* `newMessage:该群组当前最新的一条消息`\n* `total:该群组当前消息总数`\n\n注：如果开启了websocket令牌验证，且用户登录令牌token验证失败，则服务端返回\"440\"代码，并断开连接。\n```json\n\"440\"\n```\n\n***\n## HTTP接口文档\n***\n\n### 用户登录\n\n#### 接口说明\n\u003e 根据业务自定义，默认直接通过验证并返回token。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/user/login\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### 请求Body参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\npassword | 123456 | Text | 是 | 密码\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"8f2c1eb2099049eab5cad6a78a1f8285\",\n\t\"data\": \"user_info\"\n}\n```\n\n***\n\n### 获取指定消息之前的历史消息列表\n\n#### 接口说明\n\u003e 前端聊天室上拉刷新时，可调用此接口获取历史消息列表。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/group/listMessage\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### Header参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\ntoken | 84e9d36e4c7c44e0a79bb71f1b4ce9c4 | Text | 是 | 登录令牌\n\n#### 请求Body参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 指定消息的用户id\ngroupId | 1 | Text | 是 | 指定消息所属群组id\nts | 1648443134344 | Text | 是 | 指定消息的创建时间戳\ncount | 4 | Text | 是 | 要获取的历史消息数量\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"操作成功\",\n\t\"data\": [\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"1\\\",\\\"ts\\\":1648368380132}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"2\\\",\\\"ts\\\":1648368386964}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"3\\\",\\\"ts\\\":1648368388389}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"4\\\",\\\"ts\\\":1648368390249}\"\n\t]\n}\n```\n\n***\n\n### 获取一定区间内的群组消息列表\n\n#### 接口说明\n\u003e 可以给管理端用，用于查看群组消息列表。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/group/listMessage\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### Header参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\ntoken | 84e9d36e4c7c44e0a79bb71f1b4ce9c4 | Text | 是 | 登录令牌\n\n#### 请求Body参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\ngroupId | 1 | Text | 是 | 群组id\nstartPage | 0 | Text | 是 | 起始页\nendPage | 5 | Text | 是 | 终止页\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"操作成功\",\n\t\"data\": [\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"1\\\",\\\"ts\\\":1648368380132}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"2\\\",\\\"ts\\\":1648368386964}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"3\\\",\\\"ts\\\":1648368388389}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"4\\\",\\\"ts\\\":1648368390249}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"5\\\",\\\"ts\\\":1648368391742}\",\n\t\t\"{\\\"groupId\\\":\\\"1\\\",\\\"userId\\\":\\\"1\\\",\\\"info\\\":\\\"6\\\",\\\"ts\\\":1648368393362}\"\n\t]\n}\n```\n\n***\n\n### 用户撤回自己的群聊消息\n\n#### 接口说明\n\u003e 默认设定只能撤回两分钟内的消息。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/group/delMessage\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### Header参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\ntoken | 84e9d36e4c7c44e0a79bb71f1b4ce9c4 | Text | 是 | 登录令牌\n\n#### 请求Body参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\ngroupId | 1 | Text | 是 | 群组id\nts | 1648443134344 | Text | 是 | 消息创建时间戳\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"撤回消息成功\",\n\t\"data\": null\n}\n```\n\n***\n\n### 用户加入群聊\n\n#### 接口说明\n\u003e 默认设定用户进行WebSocket连接后自动加入群聊，如果改为手动加群，需要先调用此接口，加群后再进行WebSocket连接。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/user/joinGroup\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### Header参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\ntoken | 84e9d36e4c7c44e0a79bb71f1b4ce9c4 | Text | 是 | 登录令牌\n\n#### 请求Body参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\ngroupId | 3 | Text | 是 | 群组id\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"操作成功\",\n\t\"data\": null\n}\n```\n\n***\n\n### 获取用户加入的群组列表\n\n#### 接口说明\n\u003e 只返回群组id。\n\n#### 接口URL\n\u003e http://127.0.0.1:9000/user/listGroup\n\n#### 请求方式\n\u003e POST\n\n#### Content-Type\n\u003e form-data\n\n#### Header参数\n参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述\n--- | --- | --- | --- | ---\nuserId | 1 | Text | 是 | 用户id\ntoken | 84e9d36e4c7c44e0a79bb71f1b4ce9c4 | Text | 是 | 登录令牌\n\n#### 成功响应示例\n```json\n{\n\t\"code\": 200,\n\t\"msg\": \"操作成功\",\n\t\"data\": [\n\t\t\"3\",\n\t\t\"2\",\n\t\t\"1\"\n\t]\n}\n```\n\n***\n\n## 项目结构\n\n* config `配置层`\n   * IMConfig `IM基础功能配置`\n   * InterceptorConfig `接口拦截器配置`\n   * RedisConfig `Redis配置类`\n   * WebSocketConfig `websocket配置类`\n* controller `控制器层`\n   * GroupController `群组操作接口`\n   * UserController `用户操作接口`\n* dao `模板层`\n   * GroupObject `群组对象`\n   * MessageList `消息列表封装`\n   * MessageObject `消息对象`\n* interceptor `AOP拦截器`\n   * ApiInterceptor `接口拦截器`\n* server `websocket服务层`\n   * GroupChatServer `群组聊天室连接（监听群内聊天消息更新）`\n   * GroupListServer `首页群组列表连接（监听用户加入的所有群组数据更新）`\n   * RedisListenServer `Redis订阅监听服务（监听所有IM服务器接收到的消息）`\n* service `控制器服务层`\n   * GroupService `群组操作服务`\n   * UserService `用户操作服务`\n* util `工具集合`\n   * LoginUtil `登录验证工具`\n   * RedisUtil `Redis工具类`\n   * ResultUtil `http请求返回模板`\n* FastimApplication `启动类`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpwgc%2Ffast-im","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpwgc%2Ffast-im","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpwgc%2Ffast-im/lists"}