大作业|青训营笔记

308 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 篇 本次笔记将记录大项目的答辩文档

1108组青训营后端结业项目答辩汇报文档

一、项目介绍

利用Golang实现极简版抖音的服务端

项目服务地址:本地服务

Github 地址:Github地址

二、项目分工

团队成员主要贡献
田鹏飞负责数据库设计、互动接口(及社交接口中的关注操作)、中间件的开发与配置、文档撰写
赵宇轩负责后端架构设计、基础接口、Redis缓存的开发与配置、演示视频剪辑

三、项目实现

3.1 技术选型与相关开发文档

3.1.1数据库的选择与设计

数据库选择的是MySQL,对数据库操作的时候不是使用的Golang自带的sql包,而是使用的gorm。

用户表

type User struct {
   ID        int64     `json:"id"`         // 用户id
   UserName  string    `json:"user_name"`  // 用户名
   Password  string    `json:"password"`   // 用户密码
   CreatedAt time.Time `json:"created-at"` // 用户创建时间
   UpdatedAt time.Time `json:"update_at"`  // 用户上次更新用户数据的时间
}

func (User) TableName() string {
   return "users"
}

用户详情表,在实际的开发中由于注册时没有详细信息的设置,但是在Feed、用户信息等接口需要获取取这些数据,这里就只是将表建立起来,在注册账户时会同步插入一个userName。

type UserInfo struct {
   ID              int64  `json:"id"`               // 用户id
   UserName        string `json:"name"`             // 用户名称
   Avatar          string `json:"avatar"`           // 用户头像
   BackgroundImage string `json:"background_image"` // 用户个人页顶部大图
   Signature       string `json:"signature"`        // 个人简介
  
   CreatedAt time.Time `json:"created-at"` // 用户创建时间
   UpdatedAt time.Time `json:"update_at"`  // 用户上次更新用户数据的时间
}

func (UserInfo) TableName() string {
   return "user_info"
}

视频表

type Video struct {
   ID       int64  `json:"id"`        // 视频唯一标识
   UserId   int64  `json:"user_id"`   // 作者id
   Title    string `json:"title"`     // 视频标题
   PlayURL  string `json:"play_url"`  // 视频播放地址
   CoverURL string `json:"cover_url"` // 视频封面地址
   //FavoriteCount int64  `json:"favorite_count"` // 视频的点赞总数
   //CommentCount  int64  `json:"comment_count"`  // 视频的评论总数
   CreatedAt time.Time `json:"created-at"` // 视频发布时间
}

func (Video) TableName() string {
   return "videos"
}

关注表

type Follow struct {
   ID        int64
   UserId    int64 //关注者
   FollowId  int64 //被关注者
   CreatedAt time.Time
}

func (Follow) TableName() string {
   return "follow"
}

评论表

type Comment struct {
   ID        int64
   VideoId   int64
   UserId    int64
   Context   string
   CreatedAt time.Time
}

func (Comment) TableName() string {
   return "comment"
}

喜欢表

type Favorite struct {
   ID          int64 `json:"id"`
   UserID      int64 `json:"user_id"`
   VideoUserID int64 `gorm:"video_user_id"`
   VideoID     int64 `json:"video_id"`
}

func (Favorite) TableName() string {
   return "favorite"
}

3.1.2 http框架的选择

毫无疑问,http框架选择的是我们在青训营学习的hertz框架。

3.2 架构设计

3.2.1架构设计图

3.2.2项目目录结构

├─bytedance_douyin

│ ├─.idea

│ ├─biz

│ │ ├─config

│ │ ├─dao

│ │ ├─handler

│ │ ├─middleware

│ │ ├─model

│ │ │ ├─entity

│ │ │ └─vo

│ │ ├─redis

│ │ ├─router

│ │ ├─server

│ │ └─utils

│ └─static

│ └─videos

│ ├─main.go

3.3 项目代码及实现接口介绍

3.3.1项目代码

见Github项目地址:项目地址GitHub点我

3.3.2项目接口介绍

见青训营抖音项目文档:青训营抖音项目介绍文档

四、测试结果

4.1 基础接口

/douyin/feed/ - 视频流接口

{
    "status_code": 0,
    "status_msg": "视频列表返回成功",
    "next_time": 1677141884,
    "video_list": [
        {
            "author": {
                "id": 1,
                "name": "123456",
                "avatar": "",
                "background_image": "",
                "signature": "",
                "created-at": "2023-02-22T21:50:54.934+08:00",
                "update_at": "2023-02-22T21:50:54.934+08:00",
                "is_follow": false,
                "total_favorited": 0,
                "work_count": 1,
                "favorite_count": 0,
                "follow_count": 0,
                "follower_count": 0
            },
            "comment_count": 0,
            "cover_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.jpg",
            "favorite_count": 0,
            "id": 1,
            "is_favorite": false,
            "play_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.mp4",
            "title": "test1"
        }
    ]
}

/douyin/user/register/ - 用户注册接口

/douyin/user/login/ - 用户登录接口

/douyin/user/ - 用户信息

/douyin/publish/action/ - 视频投稿

/douyin/publish/list/ - 发布列表

{
    "status_code": 0,
    "status_msg": "视频列表返回成功",
    "next_time": 1677142399,
    "video_list": [
        {
            "author": {
                "id": 1,
                "name": "123456",
                "avatar": "",
                "background_image": "",
                "signature": "",
                "created-at": "2023-02-22T21:50:54.934+08:00",
                "update_at": "2023-02-22T21:50:54.934+08:00",
                "is_follow": false,
                "total_favorited": 0,
                "work_count": 1,
                "favorite_count": 0,
                "follow_count": 0,
                "follower_count": 0
            },
            "comment_count": 0,
            "cover_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.jpg",
            "favorite_count": 0,
            "id": 1,
            "is_favorite": false,
            "play_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.mp4",
            "title": "test1"
        }
    ]
}

5.2 互动接口

/douyin/favorite/action/ - 赞操作

点赞

取消点赞

/douyin/favorite/list/ - 点赞列表

{
    "status_code": 0,
    "status_msg": "获取视频列表成功",
    "next_time": 0,
    "video_list": [
        {
            "author": {
                "id": 1,
                "name": "123456",
                "avatar": "",
                "background_image": "",
                "signature": "",
                "created-at": "2023-02-22T21:50:54.934+08:00",
                "update_at": "2023-02-22T21:50:54.934+08:00",
                "is_follow": false,
                "total_favorited": 0,
                "work_count": 1,
                "favorite_count": 0,
                "follow_count": 0,
                "follower_count": 0
            },
            "comment_count": 0,
            "cover_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.jpg",
            "favorite_count": 0,
            "id": 1,
            "is_favorite": false,
            "play_url": "http://172.29.219.224:8888/static/videos/userId1/1test11677073864.mp4",
            "title": "test1"
        }
    ]
}

/douyin/comment/action/ - 评论操作

评论

取消评论

/douyin/comment/list/ - 视频评论列表

{
    "status_code": 0,
    "status_msg": "返回评论列表成功",
    "comment_list": [
        {
            "content": "1111",
            "create_date": "02-23",
            "id": 2,
            "user": {
                "id": 1,
                "name": "123456",
                "avatar": "",
                "background_image": "",
                "signature": "",
                "created-at": "2023-02-22T21:50:54.934+08:00",
                "update_at": "2023-02-22T21:50:54.934+08:00",
                "is_follow": false,
                "total_favorited": 0,
                "work_count": 0,
                "favorite_count": 0,
                "follow_count": 0,
                "follower_count": 0
            }
        }
    ]
}

5.3 社交接口

/douyin/relation/action/ - 关注操作

关注

取消关注

五、Demo 演示视频 (必填)

This content is only supported in a Feishu Docs

六、项目总结与反思

6.1目前仍存在的问题

像MySQL中dsn、ffmpeg的文件路径等都应该是写到配置文件里面的,但是在操作的过程中,通过打印测试发现配置数据是正常读取的,但是在进行功能测试时就会出现问题,一直找不到原因。

6.2已识别出的优化项

  1. 密码用MD5加密,由于MD5加密是不可逆的,避免后台的管理员能直接登录用户的账号,在MD5加密时,还设置了一个盐值,避免用户密码过于简单,可以用暴力匹配破解密码。
  2. 最开始我们对前端传入的数据在某些方面并没有进行验证,比如我们在注册时,发现app已经对密码位数进行了验证,就没有进行验证,但是后来发现可能有人恶意的向我们后端发送请求,去注册一些不合理的密码。
  3. 对于向前端返回的数据,如果有错误,我们不直接返回err.Error(),避免暴露后端的问题而是将其打印在日志中,在返回的Status.Msg中返回“操作失败”或者更为贴切场景的提示,对于错误时返回Status.Code,我们时想与前端程序员进行约定,返回不同的数字代表相对应得错误,并且将该错误对应得常树写到一个专门的Go文件中
  4. 对于点赞、关注等操作,使用了redis缓存来降低服务器的压力

6.3一些想说的话

这次的青训营我是和我舍友组的队,我们两个人都是刚接触Golang,在这个项目实现的过程中,我们遇到了很多问题,我们两个一起解决了一些,但是还有一部分没解决了。这是我第一次真正意义上进行团队开发,项目的分工也没有上面写的那样明确,我们两个人遇到了问题,都是一起合作探讨解决的,过程中我深刻感受到了合作开发带来的便利与配合时的困难,我想这也是青训营不允许单人组队的原因。最后很感谢字节跳动青训营这个项目,提供了这么一个平台和机会。