代码设计思路解析
- 导入包和结构体定义: 代码首先导入所需的包,包括Gin框架、GORM库等。同时,定义了用于API响应的结构体
VideoListResponse和用于数据库操作的结构体token。
type VideoListResponse struct {
Response
VideoList []Video `json:"video_list"`
}
type token struct {
UserId int64 `json:"user_id,omitempty"gorm:"primaryKey;autoIncrement"`
Token string `json:"token"`
}
- 提取视频封面图像函数
extractVideoCover: 这个函数的主要功能是从上传的视频文件中提取封面图像。它构建了封面图像的文件路径,并通过命令行工具ffmpeg对视频文件进行截图。然后,生成封面图像的URL并返回。这样的设计允许系统在发布视频时自动生成封面图像,增强用户体验。
func extractVideoCover(videoFilePath string) (string, error) {
coverFileName := fmt.Sprintf("%s_cover.jpg", filepath.Base(videoFilePath))
coverFilePath := filepath.Join("./public/cover/", coverFileName) // 可自定义保存路径
cmd := exec.Command("ffmpeg", "-i", videoFilePath, "-ss", "00:00:01", "-vframes", "1", coverFilePath)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("截取封面图像出错: %v\n%s", err, output)
}
coverurl := fmt.Sprintf("http://%s:8080/cover/%s", getLocalIP(), coverFileName)
fmt.Println("生成封面图像成功:", coverFilePath)
return coverurl, nil
}
-
处理视频发布请求的函数
Publish: 这个函数处理用户发布视频的请求。首先,它从请求中获取用户令牌,并尝试连接到数据库。通过令牌查询数据库,如果找到匹配的记录,则获取用户信息。接下来,它接收上传的视频文件,为其生成一个唯一的文件名,并将文件保存到指定路径。然后,调用前面定义的
extractVideoCover函数来获取视频封面图像URL。最后,将视频信息和封面URL存入数据库,完成视频发布。这样的设计考虑了用户身份验证、视频存储和封面图像生成的方方面面,构建了完整的视频发布流程。
func Publish(c *gin.Context) {
utoken := c.PostForm("token")
dsn := "host=localhost user=postgres password=281455 dbname=tiktok port=5432 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("无法连接数据库")
}
token := token{}
result := db.First(&token, "token = ?", utoken)
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "User doesn't exist"})
} else {
// 处理其他错误情况
}
} else {
// 处理找到记录的情况
}
user := User{}
db.Select("id, name, follow_count, follower_count, is_follow").
Where("Id = ?", token.UserId).First(&user)
data, err := c.FormFile("data")
if err != nil {
c.JSON(http.StatusOK, Response{
StatusCode: 1,
StatusMsg: err.Error(),
})
return
}
filename := filepath.Base(data.Filename)
finalName := fmt.Sprintf("%d_%s", user.Id, filename)
saveFile := filepath.Join("./public/videos/", finalName)
if err := c.SaveUploadedFile(data, saveFile); err != nil {
c.JSON(http.StatusOK, Response{
StatusCode: 1,
StatusMsg: err.Error(),
})
return
}
cover, err := extractVideoCover(saveFile)
if err != nil {
c.JSON(http.StatusOK, Response{
StatusCode: 1,
StatusMsg: err.Error(),
})
return
}
playurl := fmt.Sprintf("http://%s:8080/video/%s", getLocalIP(), finalName)
video := Videos{
AuthorID: user.Id,
PlayUrl: playurl,
CoverUrl: cover,
FavoriteCount: 0,
CommentCount: 0,
IsFavorite: false,
}
if err := db.Create(&video).Error; err != nil {
c.JSON(http.StatusOK, Response{
StatusCode: 1,
StatusMsg: err.Error(),
})
return
}
sqlDB, _ := db.DB()
defer sqlDB.Close()
c.JSON(http.StatusOK, Response{
StatusCode: 0,
StatusMsg: finalName + " uploaded successfully",
})
}
- 处理用户视频列表请求的函数
PublishList: 这个函数用于获取用户发布的视频列表。通过令牌查询数据库,找到匹配的用户记录。然后,根据用户ID查询数据库,获取该用户发布的视频列表。
func PublishList(c *gin.Context) {
dsn := "host=localhost user=postgres password=281455 dbname=tiktok port=5432 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("无法连接数据库")
}
utoken := c.PostForm("token")
var tokenRecord token
tokenResult := db.Where("token = ?", utoken).First(&tokenRecord)
if tokenResult.Error != nil {
if tokenResult.Error == gorm.ErrRecordNotFound {
c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "Token not found"})
} else {
// 处理其他错误情况
}
return
}
var publishvideos = []Video{}
var pdbvideolist = []Videos{}
db.Where("authorid = ?", tokenRecord.UserId).Find(&pdbvideolist)
for _, pdbvideolist := range pdbvideolist {
var user User
db.Select("id, name, follow_count, follower_count, is_follow").
Where("Id = ?", pdbvideolist.AuthorID).First(&user)
video := Video{
Id: pdbvideolist.Id,
Author: user,
PlayUrl: pdbvideolist.PlayUrl,
CoverUrl: pdbvideolist.CoverUrl,
FavoriteCount: pdbvideolist.FavoriteCount,
CommentCount: pdbvideolist.CommentCount,
IsFavorite: pdbvideolist.IsFavorite,
}
publishvideos = append(publishvideos, video)
}
c.JSON(http.StatusOK, VideoListResponse{
Response: Response{
StatusCode: 0,
},
VideoList: publishvideos,
})
}
在循环中,它从数据库获取视频信息,并构建了一个用于响应的视频列表。这样的设计为用户提供了一个查看自己发布视频列表的功能,丰富了系统的功能。
- 获取本地IP地址的函数
getLocalIP: 这个函数用于获取本地IP地址。它遍历网络接口地址,找到第一个非回环的IPv4地址,并返回。
func getLocalIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
// 遍历接口地址
for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet)
if ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil {
// 如果满足条件,返回找到的第一个合适的地址
return ipnet.IP.String()
}
}
return "" // 没有找到符合条件的地址
}
个人思考与学习笔记
这份代码展示了一个基本的视频发布与展示系统的实现,使用了Gin框架和GORM库。通过代码的解析,我对以下方面进行了思考和学习:
- Web框架和数据库库的使用: 通过阅读代码,我了解了如何使用Gin框架处理HTTP请求和路由,以及如何使用GORM库进行数据库操作。这让我更深入地理解了Web开发和数据库连接的过程。
- 视频封面图像的自动生成: 通过
extractVideoCover函数,我学到了如何使用命令行工具生成视频封面图像,并将其与视频关联。这个自动生成的设计有助于提升用户体验,同时减轻了用户的操作负担。 - 用户身份验证和数据关联: 代码中通过令牌对用户进行身份验证,然后将用户信息与视频关联。这种关联设计在构建复杂系统时非常重要,它可以帮助维护数据的一致性和完整性。
- 错误处理和异常情况: 代码中充分考虑了可能的错误情况,比如数据库连接失败、文件上传失败等。这样的错误处理设计是保障系统稳定性的关键。
- 系统功能的实现: 代码展示了视频发布和展示系统的基本功能,包括视频上传、封面图像生成、用户视频列表等。我意识到在实际项目中,需要综合考虑用户需求,实现更多的功能和交互。