各位同学朋友大家好,今天我将向大家分享我自己是如何实现大项目中的视频流/feed/的功能的。
1 准备工作
你需要一个准备一个mysql数据库用来存放数据,数据库如果是你的本机,那么很可能你的数据库别人访问不到需要自己设置,也可以自己租一个云服务器等等。还需要一个Go语言环境,我自己用的是VsCode,可能和用golang的人有些地方不同。
2 数据库配置
首先进入数据库:
在第一次进入数据库时,是需要设置密码的,可以参考下面两篇文章修改:
创建库和表,这里我使用的是SQL语句:
js
mysql> create database douyinproject;
进入数据库:
js
mysql> use douyinproject;
创建表video_infos,创建时需要定义你创建的参数的数据类型,这里我定义了author_id、play_url、cover_url、favorite_count、comment_count、title六种类型,其他类型可以参照视频流接口 - 极简版抖音 (apifox.com)去添加:
js
mysql> create table video_infos(author_id int,play_url varchar(50),cover_url varchar(50),favorite_count int,comment_count int, title varchar(50));
通常mysql的数据类型int表示整型,int64、int32都可以用它表示;varchar()表示的是mysql中的字符型括号中表示长度,与string、char对应。
之后通过在数据库中插入视频流的地址便可以通过后端访问,author_id可以递增写入,play_url和cover_url指视频ip和封面ip,这里可以自己将存储地址ip写入,例如将所有视频放入一个自建的ftp文件系统网址,不过我因为权限问题的最后没有按这样做。第二种方法是直接在网上找到视频和封面的网址,将它的地址写上(一般的短视频平台的视频都会无法加载出来,所以我推荐大家可以找一些大公司或者企业的官网上把它们的宣传片和封面地址直接写在这里)。favorite_count,comment_count直接写数字就可以,title写字。
例子(写字符型时记得要加""号):
js
mysql> insert into video_infos values(1,"https://119v.pku.edu.cn/videos/20201016-115625.mp4","https://pe.pku.edu.cn/__local/1/EB/85/7A811B57783BF4CCD549C3192B5_EC4ACC6F_A6B06.jpg",1,"jdkfaldk");
如果想修改的话需要学习一些相关语法,可以看这篇文章SQL语法大全 或者我这篇文章小白学习Gin框架以及GORM增删查改项目实践 | 青训营 - 掘金 (juejin.cn)中的Go修改数据库内容。
3 配置后端
文章采用的是基于gin框架来写的:
3.1
首先创建go.mod文件以及main.go文件:
go.mod:
js
go mod init go.mod
在这个文件中放入了自己所使用包的路径,导入包可以用以下命令,比如自己需要导入gin的包,那么应该输入命令:
js
go get -u github.com/gin-gonic/gin
之后在go.mod中就会添加到相关包路径。
3.2 main
写一下主启动函数main:
新建main.go文件并写入:
go
package main
import (
"go.mod/config" //表示在当前路径下的config文件夹中内容,主要是用来存放一些自定义的常量,例如数据库位置、密码、端口等等.
"go.mod/mysql" //数据库操作
"go.mod/router" //相关接口
"fmt"
"github.com/gin-gonic/gin" //gin的包
)
func main() {
r := gin.Default() //创建服务
if err := mysql.Init(); err != nil { //数据库启动失败的返回
fmt.Printf("mysql启动失败,err:%v\n", err)
return
}
defer mysql.Close() //数据库关闭
router.InitRouter(r) //运行操作
}
3.3 Router层
router.go,这里我们只配置/feed/:
go
package router
import (
"go.mod/mysql"
"go.mod/controller"
"github.com/gin-gonic/gin"
)
func InitRouter(r *gin.Engine) {
r.GET("/douyin/feed", VideoInfoHandler) //注意这里的接口书写一定要和前端一样不然无法响应,尤其是/这样的符号
}
//将InitRouter()中的VideoInifoHandler函数写好,主要用于视频信息处理
func VideoInfoHandler(c *gin.Context) {
data, _ := mysql.SelectVideoInfo() //获取数据库中的视频数据
ResponseSuccess(c,data) //返回相应成功的操作
}
videoresponse.go,这里主要是ResponseSuccess()操作,返回给前端响应,文档中写出需要的三个参数为status_code、satus_msg、video_list:
go
package router
import (
"go.mod/model"
"net/http"
"github.com/gin-gonic/gin"
)
type ResCode int64 //自定义status_code参数
const CodeSuccess ResCode = 0
var codeMsgMap = map[ResCode]string{ //定义status_msg
CodeSuccess: "success",
}
type ResponseData struct { //定义返回结构体,可以将其放入model层中
Code ResCode `json:"status_code"`
Msg interface{} `json:"status_msg"`
VideoInfo interface{} `json:"video_list"`
}
func (rc ResCode) Msg() string { //status_msg返回错误时的定义
msg := codeMsgMap[rc] //若错误返回空
return msg
}
func ResponseSuccess(c *gin.Context, videoList []*model.VideoInfo) { //返回响应主函数
c.JSON(http.StatusOK, &ResponseData{
Code: CodeSuccess,
Msg: CodeSuccess.Msg(),
VideoInfo: &videoList, //返回的应该为数据库中的信息,该信息videoList用mysql/feed中的SelectVideoInfo()获得
})
}
model.VideoInfo表示结构体,在model层中定义了。
3.4 mysql层
feed.go,SelectVideoInfo()的操作:
go
package mysql
import (
"github.com/22722679/douyin-project/model"
"fmt"
"go.uber.org/zap" //这里要重新go get一下
"database/sql"
)
func SelectVideoInfo() (videoList []*model.VideoInfo, err error) {
sqlStr := "select author_id, play_url, cover_url, favorite_count, comment_count, title from video_infos" //执行SQL语句
if err := db.Select(&videoList, sqlStr); err != nil {
if err == sql.ErrNoRows { //错误时输出
zap.L().Warn("数据库中没有视频")
}
}
return
}
mysql.go,执行数据库相关操作,如启动、登录、关闭数据库:
go
package mysql
import (
"go.mod/config"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
"github.com/spf13/viper"
"go.uber.org/zap"
)
var db *sqlx.DB
func Init() (err error) {
db, err = sqlx.Connect("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", config.User, config.PassWord, config.IpMessage,config.DataBase))
if err != nil {
zap.L().Error("连接数据库失败,错误码为:%v\n", zap.Error(err))
return
}
db.SetMaxOpenConns(viper.GetInt("mysql.max_open_conns")) //设置数据库的最大打开连接数
db.SetMaxIdleConns(viper.GetInt("mysql.max_idle_conns")) //设置连接空闲的最大时间,过期的连接可能会在重用之前惰性关闭。
return
}
//数据库关闭返回空
func Close() {
_ = db.Close()
}
3.5 model层
feed.go定义视频流VideoInfo结构体:
go
import "gorm.io/gorm"
//视频流信息
type VideoInfo struct {
gorm.Model
Id int `json:"id" db:"author_id"`
PlayUrl string `json:"play_url" db:"play_url"`
CoverUrl string `json:"cover_url" db:"cover_url"`
FavoriteCount int `json:"favorite_count" db:"favorite_count"`
CommentCount int `json:"comment_count" db:"comment_count"`
Title string `json:"title" db:"title"`
}
json名称与前端对应,db名称与mysql数据库中的相对应。
3.6 config
config.go:
go
const User = "root"
const PassWord = "*****" //数据库的密码
const IpMessage = "ip:3306" //自己电脑的IP和数据库使用端口,一般为3306
const DataBase = "" //数据存放的数据库名称
3.7 运行
最终该程序就写好了,只要运行就可以了。