使用golang及gorm制作一个用户的评论以及回复评论,同时删除评论后评论数通过递归查询所有的子孙评论发生改变
在前端传来用户的数据,即我评论了哪个楼主,我上一级的评论是谁,
评论:先判断是否存在楼主,其次判断是否存在父级评论,之后添加评论,最后增加评论数,储存数据库
删除评论:获取删除评论的楼主树洞,判断是否是本人或者楼主删除评论,判断是否又该评论的父级评论,通过递归算法查询所有的子孙评论,删除子孙评论,评论数减少,最后存入数据库。(在递归中,要查找子评论的子评论,同时删除子评论,减少评论数)
//递归删除所有评论的子评论
func DeleteCommentAndReplays(comment *model.TreeHoleComment) (err error) {
comment, err = mysql.GetTreeHoleCommentByID(int(comment.ID))
if err != nil {
zap.L().Error("数据库查询回复失败", zap.Error(err))
return err
}
for _, replay := range comment.CommentReplays {
err := DeleteCommentAndReplays(replay) //此处递归
if err != nil {
zap.L().Error("递归查询评论失败", zap.Error(err))
return err
}
//删除评论
err = mysql.DeleteTreeHoleComment(int(replay.ID))
if err != nil {
zap.L().Error("删除评论失败", zap.Error(err))
return err
}
//查询顶部树洞
treeHoleByID, err := mysql.GetTreeHoleByID(int(comment.TreeHoleID))
if err != nil {
zap.L().Error("通过id查询树洞错误", zap.Error(err))
return err
}
treeHoleByID.CommentNum--
//存数据库
err = mysql.UpdateTreeHole(treeHoleByID)
if err != nil {
zap.L().Error("数据库更新树洞失败", zap.Error(err))
return err
}
}
return nil
}
//树洞结构体
type TreeHole struct {
gorm.Model
User User
UserID uint `json:"userID"` //用户ID
Content string `json:"content"` //树洞内容
LikeNum uint `json:"likeNum"` //点赞数
CommentNum uint `json:"comment_num"` //评论数
Replays []TreeHoleComment `json:"replays"` //回复的评论
IsLike bool `gorm:"-" json:"is_like"` //喜欢或者不喜欢
}
//树洞评论结构体
type TreeHoleComment struct {
gorm.Model
CommentReplays []*TreeHoleComment `gorm:"foreignkey:ParentID"` //自引用
User User
UserID uint `json:"userID" ` //用户ID
Parent *TreeHoleComment `gorm:"foreignkey:ParentID"`
ParentID uint `json:"parent_id"` //评论父级ID 0
Content string `json:"content"` //内容
IsAnonymityReplay uint `json:"is_anonymity_replay"` //是否匿名回复
TreeHoleID uint `json:"tree_hole_id"` //树洞ID
}
//评论树洞
func TreeHoleComments(c *gin.Context) {
userid := GetUserIDByToken(c)
var comment *model.TreeHoleComment
err := c.ShouldBindJSON(&comment)
if err != nil {
zap.L().Error("绑定JSON失败", zap.Error(err))
ResponseError(c, CodeParamError)
return
}
//判断是否是本人发布的评论
if userid != comment.UserID {
zap.L().Error("userid与发布评论的用户不一致", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "非本人操作")
return
}
//判断是否有评论的树洞
treeHoleIsExist, err := mysql.GetTreeHoleIsExist(int(comment.TreeHoleID))
if err != nil {
zap.L().Error("数据库查询树洞失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "查询树洞失败")
return
}
if treeHoleIsExist == 0 {
zap.L().Error("数据库中没有该树洞", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库中没有该树洞")
return
}
//判断是否有该评论的父级评论
treeHoleCommentIsExist, err := mysql.GetTreeHoleCommentIsExist(int(comment.ParentID))
if err != nil {
zap.L().Error("数据库查询父级评论失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库查询父级评论失败")
return
}
if treeHoleCommentIsExist == 0 && (comment.ParentID) != 0 {
zap.L().Error("数据库中没有该评论的父级评论", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库中没有该评论的父级评论")
return
}
//添加评论
err = mysql.CreateTreeHoleComment(comment)
if err != nil {
zap.L().Error("创建树洞评论失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "创建树洞评论失败")
return
}
//评论数增加
treeHoleByID, err := mysql.GetTreeHoleByID(int(comment.TreeHoleID))
if err != nil {
zap.L().Error("通过id查询树洞错误", zap.Error(err))
ResponseErrorWithMsg(c, CodeServerBusy, "没有该树洞")
return
}
treeHoleByID.CommentNum++
//存数据库
err = mysql.UpdateTreeHole(treeHoleByID)
if err != nil {
zap.L().Error("数据库更新树洞失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "更新失败")
return
}
ResponseSuccess(c, comment)
}
//删除评论
func DeleteTreeHoleComment(c *gin.Context) {
userid := GetUserIDByToken(c)
commentID := c.Query("commentsID")
commentIDNum, err := strconv.Atoi(commentID)
if err != nil {
zap.L().Error("转数字失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "转数字失败")
return
}
comment, err := mysql.GetTreeHoleCommentByID(commentIDNum)
if err != nil {
zap.L().Error("数据库查询回复失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库查询回复失败")
return
}
//查询发表该树洞的楼主
topTreeHole, err := mysql.GetTreeHoleByID(int(comment.TreeHoleID))
//判断是否是本人发布的评论或者楼主删除
if userid != comment.UserID && userid != topTreeHole.UserID {
zap.L().Error("userid与发布评论的用户不一致", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "非本人或楼主操作")
return
}
//判断是否有评论的树洞
treeHoleIsExist, err := mysql.GetTreeHoleIsExist(int(comment.TreeHoleID))
if err != nil {
zap.L().Error("数据库查询树洞失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "查询树洞失败")
return
}
if treeHoleIsExist == 0 {
zap.L().Error("数据库中没有该树洞", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库中没有该树洞")
return
}
//判断是否有该评论的父级评论
treeHoleCommentIsExist, err := mysql.GetTreeHoleCommentIsExist(int(comment.ParentID))
if err != nil {
zap.L().Error("数据库查询父级评论失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库查询父级评论失败")
return
}
if treeHoleCommentIsExist == 0 && (comment.ParentID) != 0 {
zap.L().Error("数据库中没有该评论的父级评论", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "数据库中没有该评论的父级评论")
return
}
err = DeleteCommentAndReplays(comment)
if err != nil {
zap.L().Error("递归删除所有评论的子评论失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "递归删除所有评论的子评论失败")
return
}
//删除评论
err = mysql.DeleteTreeHoleComment(int(comment.ID))
if err != nil {
zap.L().Error("删除评论失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "删除评论失败")
return
}
//评论数减少
//查询顶部树洞
treeHoleByID, err := mysql.GetTreeHoleByID(int(comment.TreeHoleID))
if err != nil {
zap.L().Error("通过id查询树洞错误", zap.Error(err))
ResponseErrorWithMsg(c, CodeServerBusy, "没有该树洞")
return
}
treeHoleByID.CommentNum--
//存数据库
err = mysql.UpdateTreeHole(treeHoleByID)
if err != nil {
zap.L().Error("数据库更新树洞失败", zap.Error(err))
ResponseErrorWithMsg(c, CodeParamError, "更新失败")
return
}
ResponseSuccess(c, comment)
}