go-wechat:基于 Go 语言的高性能即时通讯后端服务

可用于构建类似微信的即时通讯应用,支持单聊、群聊、朋友圈、文件传输等功能,采用分层架构,接口与实现分离,事务自动管理,JWT+Redis 认证,MD5 秒传,gnet 高性能 WebSocket。【此简介由AI生成】

分支1Tags0
文件最后提交记录最后更新时间
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前
4 个月前

Go-WeChat

一个基于 Go 语言开发的高性能即时通讯后端服务,类似微信,支持单聊、群聊、朋友圈、文件传输等功能。

项目特点:采用经典分层架构,接口与实现分离,事务自动管理,JWT+Redis 认证,MD5 秒传,gnet 高性能 WebSocket


✨ 功能特性

  • 👤 用户系统

    • 用户注册/登录
    • JWT Token 认证
    • 用户信息管理
    • 用户搜索
  • 👥 好友系统

    • 添加/删除好友
    • 好友申请处理
    • 好友列表管理
    • 好友备注与分组
    • 黑名单管理
  • 💬 消息系统

    • 文本消息
    • 图片消息
    • 视频消息
    • 文件消息
    • 已读回执
    • 消息历史记录
    • 会话列表管理
  • 👨‍👩‍👧‍👦 群组系统

    • 创建/解散群组
    • 群成员管理
    • 群角色设置(群主/管理员/成员)
    • 入群申请/邀请(需被邀请人同意)
    • 群公告
    • 邀请码加群
    • 群昵称设置
    • 成员禁言管理
    • 群主转让
  • 📇 通讯录

    • 好友列表展示
    • 群聊列表展示
    • 快速发起会话
  • 🖼️ 文件上传

    • 支持 MinIO 对象存储
    • 图片压缩处理
    • 视频封面生成
    • MD5 秒传机制
    • 分类型存储管理
  • 📱 朋友圈

    • 发布动态(文字/图片/视频)
    • 支持 Markdown 编辑器
    • 代码语法高亮(PrismJS)
    • 点赞/取消点赞
    • 评论功能
    • 动态可见性控制
  • 实时通信

  • WebSocket 长连接

  • 基于 gnet 的高性能网络框架

  • 支持多端登录

  • 心跳检测


🛠️ 技术栈

技术 版本 用途
Go 1.25+ 编程语言
Gin v1.12 Web 框架
GORM v1.31 ORM 框架
MySQL 8.0+ 关系型数据库
Redis 6.0+ 缓存、Token 存储
MinIO 最新版 对象存储
Zap v1.27 结构化日志
gnet v2.9 高性能网络框架
JWT v5 身份认证
bcrypt 最新版 密码加密

🏗️ 架构设计

分层架构

┌─────────────────────────────────────────────────────────────┐
│                      Controller 层                           │
│   (HTTP 处理器 - 接收请求、参数校验、调用 Service)              │
├─────────────────────────────────────────────────────────────┤
│                      Service 层                              │
│   (业务逻辑层 - 实现接口,处理核心业务)                         │
│   ├── 接口定义: service/*.go                                 │
│   └── 实现: service/impl/*.go                                │
├─────────────────────────────────────────────────────────────┤
│                       DAO 层                                 │
│   (数据访问层 - 数据库 CRUD 操作)                              │
├─────────────────────────────────────────────────────────────┤
│                      Models 层                               │
│   (数据模型 - 定义结构体、DTO、枚举)                           │
├─────────────────────────────────────────────────────────────┤
│                   基础设施层                                  │
│   MySQL / Redis / MinIO / WebSocket / Logs                   │
└─────────────────────────────────────────────────────────────┘

核心设计亮点

1. 事务自动管理(Middleware 模式)

通过 Gin 中间件实现事务的自动开启、提交和回滚:

// middleware/transaction.go
func TransactionMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        tx := mysql.DB.Begin()
        c.Set(TransactionKey, tx)  // 将事务存入上下文
        c.Next()
        
        // 根据响应状态自动提交或回滚
        if c.Writer.Status() >= 400 {
            tx.Rollback()
        } else {
            tx.Commit()
        }
    }
}

// DAO 层自动获取事务
func DB(c *gin.Context) *gorm.DB {
    if tx, exists := c.Get(TransactionKey); exists {
        return tx.(*gorm.DB)
    }
    return mysql.DB
}

优势

  • 业务代码无需关心事务管理
  • 自动根据 HTTP 响应状态决定提交/回滚
  • 支持事务嵌套和手动控制

2. JWT + Redis 双 Token 验证

// utils/jwt.go
func GenerateToken(userID uint64, username string, source Source) (string, error) {
    // 生成 JWT Token
    token, err := jwt.NewWithClaims(...).SignedString(JwtKey)
    
    // 存入 Redis,支持多端登录管理和主动失效
    key := "user:token:" + uuid
    redis.Rdb.Set(ctx, key, token, TokenExpire)
    
    return token, nil
}

func ParseToken(tokenStr string) (*Claims, error) {
    // 解析 JWT
    claims, _ := jwt.ParseWithClaims(...)
    
    // 校验 Redis 是否存在(支持登出失效)
    redisToken, _ := redis.Rdb.Get(ctx, key).Result()
    if redisToken != tokenStr {
        return nil, errors.New("token 已过期或已退出")
    }
    return claims, nil
}

优势

  • Token 可主动失效(登出功能)
  • 支持多端登录控制
  • 可扩展单点登录限制

3. 文件秒传机制

// service/impl/file_service_impl.go
func (s *FileService) UploadFile(...) (*models.FileUploadResponse, error) {
    // 计算文件 MD5
    md5Hash, _ := calculateMD5(file)
    
    // 检查是否已存在
    if existingFile, _ := dao.GetFileUploadByMD5(md5Hash); existingFile != nil {
        return existingFile.ToResponse(), nil  // 秒传:直接返回已有文件
    }
    
    // 不存在则上传...
}

优势

  • 节省存储空间
  • 提升上传速度
  • 减少网络带宽

4. 接口与实现分离

// service/user_service.go - 接口定义
type IUserService interface {
    GetUserInfo(id uint64) *models.User
    Register(req *models.UserRegisterRequest) (*models.LoginResponse, error)
    Login(req *models.UserLoginRequest) (*models.LoginResponse, error)
}

// service/impl/user_service_impl.go - 实现
type UserService struct{}

func (u *UserService) Register(req *models.UserRegisterRequest) (*models.LoginResponse, error) {
    // 业务逻辑实现
}

// controller 中注入使用
var userService = &impl.UserService{}

优势

  • 便于单元测试(可 Mock 接口)
  • 支持实现替换(如换缓存框架)
  • 符合依赖倒置原则

5. WebSocket 高性能设计

基于 gnet 实现,采用 Reactor 模式:

// ws/server.go
type Server struct {
    handler Handler           // 业务处理器
    manager *ConnManager      // 连接管理器
    worker  *WorkerPool       // 工作协程池
}

// 配置选项
func DefaultOptions() Options {
    return Options{
        Port:            "9501",
        ReadBufferCap:   16 * 1024,
        IdleTimeout:     60 * time.Second,
        Multicore:       true,
        LockOSThread:    true,
    }
}

优势

  • 百万级并发连接
  • 零拷贝网络 I/O
  • 多核 CPU 亲和性绑定

📁 项目结构

go-wechat/
├── main.go                 # 程序入口
├── application.yml         # 配置文件
├── go.mod                  # 模块定义
│
├── controller/             # 控制器层(HTTP 处理器)
│   ├── user_controller.go      # 用户相关接口
│   ├── friend_controller.go    # 好友相关接口
│   ├── group_controller.go     # 群组相关接口
│   ├── message_controller.go   # 消息相关接口
│   ├── file_controller.go      # 文件上传接口
│   └── moment_controller.go    # 朋友圈接口
│
├── service/                # 业务逻辑接口定义
│   ├── user_service.go
│   ├── friend_service.go
│   ├── group_service.go
│   ├── message_service.go
│   ├── file_service.go
│   └── moment_service.go
│
├── service/impl/           # 业务逻辑实现
│   ├── user_service_impl.go
│   ├── friend_service_impl.go
│   ├── group_service_impl.go
│   ├── message_service_impl.go
│   ├── file_service_impl.go
│   └── moment_service_impl.go
│
├── dao/                    # 数据访问层
│   ├── dao.go              # 事务管理封装
│   ├── user_dao.go
│   ├── friend_dao.go
│   ├── group_dao.go
│   ├── message_dao.go
│   ├── file_dao.go
│   └── moment_dao.go
│
├── models/                 # 数据模型
│   ├── User.go             # 用户模型
│   ├── friend.go           # 好友模型
│   ├── group.go            # 群组模型
│   ├── message.go          # 消息模型
│   ├── file.go             # 文件模型
│   └── moment.go           # 朋友圈模型
│
├── router/                 # 路由配置
│   └── router.go
│
├── middleware/             # 中间件
│   └── transaction.go      # 事务中间件
│
├── config/                 # 配置管理
│   └── config.go           # YAML 配置读取
│
├── mysql/                  # MySQL 连接
│   └── mysql.go
│
├── redis/                  # Redis 连接
│   └── redis.go
│
├── minio/                  # MinIO 对象存储
│   └── minio.go
│
├── ws/                     # WebSocket 服务
│   ├── server.go           # 服务器实现
│   ├── handler.go          # Handler 接口定义
│   ├── chat_handler.go     # 聊天业务处理器
│   ├── manager.go          # 连接管理器
│   ├── pool.go             # 协程池
│   └── worker.go           # 工作协程
│
├── utils/                  # 工具函数
│   └── jwt.go              # JWT 生成与解析
│
├── logs/                   # 日志配置
│   └── log.go              # Zap 日志初始化
│
├── common/                 # 通用组件
│   └── common.go           # 统一响应、异常处理、JWT 中间件
│
├── templates/              # HTML 模板
│   ├── login.html
│   ├── register.html
│   ├── chat.html
│   └── moment.html
│
└── static/                 # 静态资源
    ├── css/
    └── layui/

🚀 快速开始

环境要求

  • Go 1.25+
  • MySQL 8.0+
  • Redis 6.0+
  • MinIO (可选,用于文件存储)

1. 克隆项目

git clone https://github.com/yourusername/go-wechat.git
cd go-wechat

2. 安装依赖

go mod download

3. 配置数据库

创建 MySQL 数据库:

CREATE DATABASE `go-wechat` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4. 修改配置

编辑 application.yml

server:
  port: 8084

mysql:
  host: 127.0.0.1
  port: 3306
  username: root
  password: your_password
  database: go-wechat
  charset: utf8mb4

minio:
  endpoint: 127.0.0.1
  port: 9000
  accessKey: your_access_key
  secretKey: your_secret_key
  bucketName: go-wechat
  useSSL: false

redis:
  host: 127.0.0.1
  port: 6379
  password: ""
  database: 0

5. 启动服务

go run main.go

或编译运行:

go build -o go-wechat.exe
./go-wechat.exe

启动成功后将看到:

╔══════════════════════════════════════════════════════════╗
║                    服务器启动成功                        ║
╠══════════════════════════════════════════════════════════╣
║  登录页面: http://localhost:8084/login                   ║
║  注册页面: http://localhost:8084/register                ║
║  聊天页面: http://localhost:8084/chat                    ║
║  朋友圈:   http://localhost:8084/moment                  ║
╚══════════════════════════════════════════════════════════╝

6. 访问服务

页面 URL 功能说明
登录页面 http://localhost:8084/login 用户登录
注册页面 http://localhost:8084/register 用户注册
聊天页面 http://localhost:8084/chat 聊天、通讯录、群聊
朋友圈 http://localhost:8084/moment 动态发布与浏览

📡 API 接口

统一响应格式

{
  "code": 200,
  "msg": "success",
  "data": {}
}

用户模块

方法 路径 说明 认证
POST /api/user/register 用户注册
POST /api/user/login 用户登录
GET /api/user/current 获取当前用户
POST /api/user/logout 用户登出
GET /api/users/search 搜索用户
GET /api/user/getBy/:id 获取用户信息

好友模块

方法 路径 说明 认证
POST /api/friend/request/send 发送好友申请
POST /api/friend/request/handle 处理好友申请
GET /api/friend/request/received 获取收到的好友申请
GET /api/friend/request/sent 获取发出的好友申请
GET /api/friend/list 获取好友列表
GET /api/friend/blacklist 获取黑名单列表
POST /api/friend/remark 更新好友备注
POST /api/friend/group 移动好友到分组
POST /api/friend/block 拉黑/移出黑名单
DELETE /api/friend/:id 删除好友
GET /api/friend/is-friend/:id 检查是否为好友

好友分组模块

方法 路径 说明 认证
POST /api/friend/group/create 创建好友分组
GET /api/friend/group/list 获取好友分组列表
PUT /api/friend/group/:id 更新好友分组
DELETE /api/friend/group/:id 删除好友分组

群组模块

方法 路径 说明 认证
POST /api/group/create 创建群组
PUT /api/group/update 更新群组信息
DELETE /api/group/dissolve/:id 解散群组
GET /api/group/info/:id 获取群组详情
GET /api/group/list 获取我的群组列表
GET /api/group/search 搜索群组
POST /api/group/join-by-code 通过邀请码加入群组

群成员模块

方法 路径 说明 认证
POST /api/group-member/invite 邀请成员入群
POST /api/group-member/leave 退出群组
DELETE /api/group-member/kick 踢出成员
GET /api/group-member/list/:id 获取群成员列表
PUT /api/group-member/nickname 修改群昵称
POST /api/group-member/mute 设置成员禁言
POST /api/group-member/transfer 转让群主
POST /api/group-member/set-admin 设置/取消管理员

入群申请模块

方法 路径 说明 认证
POST /api/group-join/handle 处理入群申请/邀请
GET /api/group-join/requests/:id 获取群申请列表
GET /api/group-join/my-requests 获取我的申请记录
GET /api/group-join/pending-invites 获取待处理邀请
GET /api/group-join/pending-invites-count 获取待处理邀请数量

消息模块

方法 路径 说明 认证
GET /api/conversations 获取会话列表
GET /api/messages/history 获取历史消息

文件模块

方法 路径 说明 认证
POST /api/file/upload 通用文件上传
POST /api/file/upload/image 图片上传(支持压缩)
POST /api/file/upload/video 视频上传(生成封面)
POST /api/file/check-md5 MD5 秒传检查
GET /api/file/list 获取文件列表
GET /api/file/list/:type 按类型获取文件列表
GET /api/file/:id 获取文件详情
DELETE /api/file/:id 删除文件

朋友圈模块

方法 路径 说明 认证
POST /api/moments 发布动态
GET /api/moments 获取好友动态列表
GET /api/moments/user/:user_id 获取指定用户动态
GET /api/moments/:id 获取动态详情
DELETE /api/moments/:id 删除动态
POST /api/moments/:id/like 点赞
DELETE /api/moments/:id/like 取消点赞
POST /api/moments/:id/comment 评论
DELETE /api/moments/comment/:id 删除评论

🔌 WebSocket 接口

WebSocket 服务运行在 ws://localhost:9501

连接方式

const ws = new WebSocket('ws://localhost:9501?token=your_jwt_token');

ws.onopen = () => {
    console.log('连接成功');
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    console.log('收到消息:', msg);
};

消息格式

{
  "type": 1,
  "from": 10001,
  "from_name": "张三",
  "to": 10002,
  "content": "你好",
  "room_id": "private_10001_10002",
  "timestamp": 1714023456,
  "image_url": "",
  "width": 0,
  "height": 0,
  "video_url": "",
  "cover_url": "",
  "duration": 0,
  "file_url": "",
  "file_name": "",
  "file_size": 0
}

消息类型

类型 说明
MessageTypeText 1 文本消息
MessageTypeImage 2 图片消息
MessageTypeVideo 3 视频消息
MessageTypeFile 4 文件消息
MessageTypeSystem 5 系统消息

房间 ID 格式

类型 格式 示例
单聊 private_小ID_大ID private_10001_10002
群聊 group_群ID group_5

群聊消息广播

群聊消息通过 WebSocket 自动广播给所有在线群成员:

// 服务端处理流程
1. 接收消息 -> 解析 room_id (格式: group_群ID)
2. 查询该群所有成员
3. 遍历在线成员,通过 userConns 映射找到连接
4. 向每个在线成员转发消息

📝 代码规范

1. 包命名规范

  • 使用小写字母,不带下划线
  • 简洁明了,如 controller, service, dao
  • 模块路径:com.zhangmeng/go-wechat

2. 接口与实现分离

// service/user_service.go - 接口定义
type IUserService interface {
    GetUserInfo(id uint64) *models.User
    Register(req *models.UserRegisterRequest) (*models.LoginResponse, error)
}

// service/impl/user_service_impl.go - 实现
type UserService struct{}

func (u *UserService) GetUserInfo(id uint64) *models.User {
    if id == 0 {
        panic("用户ID不合法")
    }
    return dao.GetUserById(id)
}

3. 模型定义规范

type User struct {
    ID        uint64    `gorm:"primaryKey;autoIncrement" json:"id"`
    Username  string    `gorm:"size:50;not null;uniqueIndex" json:"username"`
    Password  string    `gorm:"size:255;not null" json:"-"`  // 敏感字段不返回
    CreatedAt time.Time `json:"created_at"`
}

// DTO 分离
type UserLoginRequest struct {
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

// 转换方法
func (u *User) ToResponse() UserResponse {
    return UserResponse{
        ID:       u.ID,
        Username: u.Username,
    }
}

4. 枚举定义

type MessageType int

const (
    MessageTypeText   MessageType = iota + 1 // 1 - 文本
    MessageTypeImage                         // 2 - 图片
    MessageTypeVideo                         // 3 - 视频
)

// 实现 String() 方法
func (mt MessageType) String() string {
    switch mt {
    case MessageTypeText:
        return "text"
    case MessageTypeImage:
        return "image"
    default:
        return "unknown"
    }
}

5. DAO 层写法

// 直接使用全局 DB 实例
func GetUserById(id uint64) *models.User {
    var user models.User
    if err := mysql.DB.First(&user, id).Error; err != nil {
        return nil
    }
    return &user
}

// 支持事务的版本
func GetUserByIdWithTx(tx *gorm.DB, id uint64) *models.User {
    var user models.User
    if err := tx.First(&user, id).Error; err != nil {
        return nil
    }
    return &user
}

6. 错误处理

// Service 层返回 error
func (u *UserService) Register(req *models.UserRegisterRequest) (*models.LoginResponse, error) {
    if dao.CheckUsernameExists(req.Username) {
        return nil, errors.New("用户名已存在")
    }
    // ...
}

// Controller 层统一处理
func (uc *UserController) Register(c *gin.Context) {
    resp, err := userService.Register(&req)
    if err != nil {
        c.JSON(200, common.Fail(err.Error()))
        return
    }
    c.JSON(200, common.Success(resp))
}

7. 日志规范

// 使用 Zap 结构化日志
logs.LogInfo("用户登录成功", zap.Uint64("user_id", user.ID))
logs.LogError("数据库连接失败", zap.Error(err))

// 自动记录 HTTP 请求
r.Use(logs.ZapLoggerMiddleware(logs.Logger), gin.Recovery())

🔄 项目启动流程

func main() {
    r := router.InitRoute()           // 1. 初始化路由
    mysql.InitMySQL()                 // 2. 连接 MySQL
    mysql.CreateUpdateMysqlData()     // 3. 自动建表/迁移
    minio.InitMinIO()                 // 4. 连接 MinIO
    redis.InitRedis()                 // 5. 连接 Redis
    go startWebSocketServer()         // 6. 启动 WebSocket(协程)
    runHttpServer(r)                  // 7. 启动 HTTP 服务(主线程)
}

优雅关闭

// 监听系统退出信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit

// 关闭资源
mysql.CloseMySQL()
redis.CloseRedis()
srv.Shutdown(ctx)  // 优雅关闭 HTTP 服务

📄 许可证

MIT License

🤝 贡献

欢迎提交 Issue 和 Pull Request!


📧 联系方式

如有问题,请提交 Issue 或联系项目维护者。

项目介绍

可用于构建类似微信的即时通讯应用,支持单聊、群聊、朋友圈、文件传输等功能,采用分层架构,接口与实现分离,事务自动管理,JWT+Redis 认证,MD5 秒传,gnet 高性能 WebSocket。【此简介由AI生成】

定制我的领域