青训营项目--极简版抖音总结

采用 MVC 结构,使用 Gin 作为 Web 框架,Redis 作为缓存框架,MySQL 作为持久层框架。

项目开发介绍

团队分工

小组一共七个人,可能年后大家都比较忙,只有我一人参与实际开发。

项目简介

本项目是第五届字节跳动青训营后端基础班大作业,在该项目之前只实现过简单的接口服务器,没有接触过golang,因此在实现的过程中借鉴了一些往届优秀作品。本项目采用 MVC 分层设计模型分离模型层、视图层和控制层,从而降低代码的耦合度,提高项目的可维护性。

1
2
3
4
5
       ┌─────────┐      ┌─────────┐      ┌─────────┐
──req──► ├──────► ├──────► │
Gin │ │ Redis │ │ MySQL │
◄─resp─┤ ◄──────┤ ◄──────┤ │
└─────────┘ └─────────┘ └─────────┘

极简版抖音项目划分为两大方向,互动方向和社交方向,两个方向均包含基础功能内容,在扩展功能上有所不同,具体内容如下:

  • 视频:视频推送、视频投稿、发布列表
  • 用户:用户注册、用户登录、用户信息
  • 点赞:点赞操作、点赞列表
  • 评论:评论操作、评论列表
  • 关注:关注操作、关注列表、粉丝列表
  • 消息:聊天操作(暂未实现)

技术速览

1. 使用redis加速点赞和关注过程

简单分析抖声项目可知,整个抖声app,点赞和关注是很明显的性能热点。

为此我将点赞和关注对数据库的变化用redis来做一些数据的缓存,比如该视频是否被点赞以及该用户是否被关注等等过程。

2. 使用gorm建表

数据库需要额外建立中间表实现多对多关系,gorm可以自动给多对多关系建立中间表,只需要互相持有对方的切片类型,然后再指定many2many字段即可。

image-20230220165140537

3. gin框架中间件复用代码

使用gin框架的中间件实现 JWT鉴权、密码加密存储和userId的解析验证。具体有以下中间件:

  • JWTMidWare:从JWT中解析出user_id
  • SHAMiddleWare:使用SHA1算法加密密码
  • UserIdVerify:解析并验证user_id

4. 安全防御措施

具体措施主要有以下几点:

  • 规范使用gorm操作sql语句,可防止sql注入
  • 用户密码进行SHA1加密,这个过程设置在中间件中。
  • 使用JWT用户鉴权,并加入到中间件过程中。
  • 文件合法性检验,主要是对视频的文件格式是否支持的校验。
  • 保持文件的唯一性,主要保持每次上传文件名称的唯一性,通过用户id和用户上传的视频数量进行捆绑得到一个唯一的文件名称。
  • 所有的参数均在service层的第一个阶段完成校验。

5. ffmpeg切片得到封面

首先应安装ffmpeg,并添加到系统路径。我使用ffmpeg-go从视频中截取封面的函数GetSnapshot,添加ffmpeg-go依赖:

1
go get github.com/u2takey/ffmpeg-go

GetSnapshot函数默认生成格式未jpg的封面图片,该函数有三个参数:

  • videoPath: 视频文件地址
  • snapshotPath: 生成图片的地址
  • frameNum: 获取第几帧

6. 高度定制化的配置

整个项目的环境依赖的配置均通过config文件夹里面的config.toml文件进行管理,这样增加了环境配置的灵活性,配置如下,注释也写的很清楚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#关系型数据库配置
[mysql]
host = "127.0.0.1"
port = 3306
database = "dousheng"
username = "root"
password = "******"
charset = "utf8"
parse_time = true
loc = "Local"

#nosql配置
[redis]
host = "127.0.0.1"
port = 6379
database = 0

#记录当前服务器的ip和启动端口号,当前服务器的ip用于生成对应的视频链接地址
[server]
ip = "******"
port = 8087

项目说明

1. 架构说明

青训营大作业架构说明

以用户登录模块为例共需要经过以下过程

  1. 首先进入中间件SHAMiddleWare内的函数逻辑,得到password明文加密后调用gin.Context的Set方法设置到context对象中。随后调用next()方法继续下层路由。
  2. 接着进入handler层UserLoginHandler函数逻辑,该函数负责从请求参数和context对象中读取username和password参数,并将得到的数据以规定的格式传给前端,获取相关数据的具体操作在service层中的QueryUserLogin函数中实现。
  3. 进入service层QueryUserLogin函数逻辑,执行三个过程:checkNum,prepareData,packData。也就是检查参数、准备数据、打包数据,准备数据的过程中会调用model层的UserLoginDAO,从数据持久层中获取数据。
  4. 进入service层UserLoginDAO的逻辑,执行最终的数据库请求过程,返回给上层。

2. 数据库说明

3. 遇到的问题

4. 可改进的地方

  1. 很多执行逻辑可以通过并行优化。
  2. 未增加日志系统。
  3. 未用到集群、微服务等架构。
  4. 未使用对象存储来进行视频的存储。
  5. 密码的加密没有进行加盐处理。
  6. 使用gorm时,使用了原始的sql命令。

5. 项目运行

本项目运行不需要手动建表,项目启动后会自动建表。

运行所需环境:

  • mysql 5.7及以上
  • redis 5.0.14及以上
  • ffmepg(已放入lib自带,用于对视频切片得到封面
  • 需要gcc环境(主要用于cgo,windows请将mingw-w64设置到环境变量

运行需要更改配置:

进入config目录更改对应的mysql、redis、server、path信息。

  • mysql:mysql相关的配置信息
  • redis:redis相关配置信息
  • server:当前服务器(当前启动的机器)的配置信息,用于生成对应的视频和图片链接
  • path:其中ffmpeg_path为lib里的文件路径,static_source_path为本项目的static目录,这里请根据本地的绝对路径进行更改

完成config配置文件的更改后,需要再更改conf.go里的解析文件路径为config.toml文件的绝对路径,内容如下:

if _, err := toml.DecodeFile(“你的绝对路径\config.toml”, &Info); err != nil { panic(err) }

运行所需命令:

1
2
cd .\dousheng\
go run main.go

个人收获

由于第一次接触到这类项目,本科期间主要做的前端后端只做过简单的API服务器,所以有很多东西之前没有接触过,这次的项目可以说是边学习边coding的过程,阅读往届优秀作品的源码也让我受益良多。

  1. 学会对整个项目进行MVC分层处理。
  2. 学会以更合理的方式组织代码(项目结构划分 函数名规范等),提高代码可读性。
  3. 学会使用gin框架,使用gin框架实现路由分发。
  4. 学会使用gorm框架,该框架可以自动完成整个建表过程,按照规范使用gorm能够防止sql注入。
  5. 学会使用JWT鉴权,并利用gin框架提供的中间件实现鉴权模块。
  6. 学会MySQL中的多对多关系映射以及一对多等等关系的映射。
  7. 学会Redis的使用。

青训营项目--极简版抖音总结
http://example.com/2023/02/20/青训营项目--极简版抖音总结/
作者
LuckyDai
发布于
2023年2月20日
更新于
2023年2月23日
许可协议