您的位置:首页 > 财经 > 产业 > 高端网站建设软件开发_平台网站建设方案书_网络运营课程培训班_seo是什么味

高端网站建设软件开发_平台网站建设方案书_网络运营课程培训班_seo是什么味

2025/3/13 17:49:51 来源:https://blog.csdn.net/weixin_54385104/article/details/146210114  浏览:    关键词:高端网站建设软件开发_平台网站建设方案书_网络运营课程培训班_seo是什么味
高端网站建设软件开发_平台网站建设方案书_网络运营课程培训班_seo是什么味

搭建个人论坛

在这里插入图片描述

项目地址:MyForum: go+gin+vue搭建论坛 - Gitee.com

PS:有些地方没有写好,请选择性查看

初始化项目

  1. 创建目录结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 利用ini配置初始化框架
[server]
AppMode = debug
HttpPort = :3000
JwtKey = "dhjasdkajh321"[database]
Db = mysql
DbHost = localhost
DbPort = 3306
DbUser = root
DbPassWord = flzx3qc
DbName = gForum
package configimport ("fmt""gopkg.in/ini.v1"
)var (AppMode stringHttpPort  stringJwtKey stringDb stringDbHost stringDbPort stringDbUser stringDbPassWord stringDbName string
)func init(){file, err := ini.Load("config/config.ini")if err!=nil{fmt.Println("参数初始化错误:",err)}LoadServer(file)LoadDataBase(file)
}func LoadServer(file *ini.File){AppMode = file.Section("server").Key("AppMode").MustString("debug")HttpPort = file.Section("server").Key("HttpPort").MustString("3000")JwtKey = file.Section("server").Key("JwtKey").MustString("dhajsfkas")
}func LoadDataBase(file *ini.File){Db = file.Section("databse").Key("Db").MustString("")DbHost = file.Section("databse").Key("DbHost").MustString("")DbPort = file.Section("databse").Key("DbPort").MustString("")DbUser = file.Section("databse").Key("DbUser").MustString("")DbPassWord = file.Section("databse").Key("DbPassWord").MustString("")DbName = file.Section("databse").Key("DbName").MustString("")
}
  1. 搭建gin框架
package myforumimport "MY-FORUM/routers"func main() {routers.InitRouter()
}
package routersimport ("MY-FORUM/config""github.com/gin-gonic/gin"
)func InitRouter() {gin.SetMode(config.AppMode)r := gin.Default()r.Run(config.HttpPort)
}

注册登录模块

创建数据库

package mainimport ("MY-FORUM/models""MY-FORUM/routers"
)func main() {// 连接数据库models.InitDb()// 配置路由routers.InitRouter()
}
package modelsimport ("MY-FORUM/config""fmt""time""gorm.io/driver/mysql""gorm.io/gorm"
)var db *gorm.DB
var err errorfunc InitDb(){dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local",config.DbUser, config.DbPassWord, config.DbHost, config.DbPort, config.DbName)db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})if err!=nil{fmt.Println("数据库连接失败", err)}sqlDB, err := db.DB()if err!=nil{fmt.Println("数据库连接失败:", err)}// 模型迁移db.AutoMigrate(&User{})// 设置连接池最大闲置连接数sqlDB.SetMaxIdleConns(10)// 设置数据库的最大连接数量sqlDB.SetMaxOpenConns(100)// 设置连接的最大可复用时间sqlDB.SetConnMaxLifetime(10*time.Second)
}
package modelsimport "gorm.io/gorm"type User struct {gorm.ModelUserId int64 `gorm:"type:bigint(20);primaryKey;autoIncrement" josn:"userid"`UserName string `gorm:"type:varchar(64);not null" json:"username"`PassWord string `gorm:"type:varchar(64);not null" json:"password"`Email string `gorm:"type:varchar(64)" json:"email"`Gender int `gorm:"type:tinyint(4)" json:"gender"`Role int `gorm:"type:tinyint(4);default:1" json:"role"`
}

注册

  1. 定义注册接收表单结构体,并利用validator进行参数校验设置

PS:binding在绑定时进行校验,validate需要手动调用函数进行校验(参考:Go 验证器 validator 详解 | Go 技术论坛)

type UserSignUp struct{UserName string `json:"username" validate:"required"`PassWord string `json:"password" validate:"required"`ConfirmPassWord string `json:"confirm_password" validate:"required,eqfield=PassWord"`
}
  1. 进行gorm操作

查询用户名是否已经存在

// 判断username是否已经存在
func FindUserNameExist(username string)bool{var user Usererr := db.Where("user_name = ?", username).First(&user).Errorif err!=nil{fmt.Println("用户名称查询失败", err)}if user.ID > 0{return true}else{return false}
}

添加用户

// 添加用户
func AddUser(user User)int{err := db.Create(&user).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}
  1. 进行api函数的编写
func SignUp(c *gin.Context){var userSignUp models.UserSignUp_ = c.ShouldBind(&userSignUp)err := translater.Validate.Struct(userSignUp)// 参数校验有问题if err!=nil{msg := []string{}for _, err := range err.(validator.ValidationErrors) {msg = append(msg, err.Translate(translater.Trans))}fmt.Println(msg)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : userSignUp,})c.Abort()return}username := userSignUp.UserNamepassword := userSignUp.PassWordif models.FindUserNameExist(username){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USERNAME_IS_EXIST),"data" : userSignUp,})c.Abort()return}user := models.User{UserName: username,PassWord: password,}code := models.AddUser(user)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : userSignUp,})
}
  1. 注册路由
func InitUserRouter(r *gin.Engine){UserRouter := r.Group("v1/user")UserRouter.POST("add", controller.SignUp) // 用户注册
}

登录

  1. 定义接收登录表达信息的结构体
type UserLogin struct{UserName string `json:"username" validate:"required"`PassWord string  `json:"password" validate:"required"`AccessToken stringRefreshToken string
}
  1. 在库中查询密码
// 获取用户密码
func GetPassWord(username string)string{var user Usererr := db.Where("user_name = ?", username).First(&user).Errorif err!=nil{fmt.Println("密码获取失败", err)}return user.PassWord
}
  1. 获取Token
package jwtimport ("MY-FORUM/config""errors""time""github.com/dgrijalva/jwt-go"
)type MyClaims struct {UserName string `json:"username"`jwt.StandardClaims
}var mySecret = []byte(config.JwtKey)func keyFunc(_ *jwt.Token) (i interface{}, err error) {return mySecret, nil
}const tokenExpire = 2*time.Hour// 生成accessToken refreshToken
func GenToken(username string) (aToken, rToken string, err error) {// 创建一个自己的声明c := MyClaims{username,jwt.StandardClaims{	// JWT规定的7个官方字段ExpiresAt: time.Now().Add(tokenExpire).Unix(), // 过期时间Issuer:    "why",                                 // 签发人},}// 加密并获得完整的编码后的字符串tokenaToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString(mySecret)// refresh token 不需要存任何自定义数据rToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{ExpiresAt: time.Now().Add(time.Second * 30).Unix(), // 过期时间Issuer:    "bluebell",                              // 签发人}).SignedString(mySecret)// 使用指定的secret签名并获得完整的编码后的字符串tokenreturn
}
  1. 编写登录api
// 登录
func Login(c *gin.Context){var userLogin models.UserLogin_ = c.ShouldBind(&userLogin)err := Validate.Struct(userLogin)// 参数校验错误if err!=nil{msg := []string{}for _, err := range err.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : userLogin,})c.Abort()return}// 判断用户是否存在if !models.FindUserNameExist(userLogin.UserName){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_EXIST),"data" : userLogin,})c.Abort()return}// 验证密码是否正确password := encrypt.GenerateSpw(userLogin.PassWord)truePassword := models.GetPassWord(userLogin.UserName)if password!=truePassword{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.PASSWORD_IS_WRONG),"data" : userLogin,})c.Abort()return}// 获取tokenatoken,rtoken, err := jwt.GenToken(userLogin.UserName)if err != nil {c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.TOKEN_GET_ERROR),"data" : userLogin,})c.Abort()return}userLogin.AccessToken = atokenuserLogin.RefreshToken = rtokenc.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.SUCCES),"data" : userLogin,})
}

鉴权

jwt鉴权中间件

func JwtAuthMiddle() func(c *gin.Context){return func(c *gin.Context){// 验证header中是否有AuthorizationauthHeader := c.GetHeader("Authorization")if authHeader=="" || !strings.HasPrefix(authHeader,"Bearer "){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : "用户权限不足",})c.Abort()return}// 解析atokenatoken := authHeader[7:]claims, err := jwt.ParseToken(atoken)if err!=nil{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.TOKEN_PARSE_ERROR),"data" : atoken,})c.Abort()return}// 验证用户username := claims.UserNameif !models.FindUserNameExist(username){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_EXIST),"data" : username,})c.Abort()return}// 将username写入上下文c.Set("username", username)c.Next()}
}

rtoken refresh atoken

// rtoken刷新atoken
func RefreshToken(atoken, rtoken string)(token string, err error){// 判断rtoken是否有效if _,err = jwt.Parse(rtoken, keyFunc);err!=nil{return}// 从旧的atoken中解析出来usernameclaims, err := ParseToken(atoken)// 如果还未过期,则返回开始的atokenif err==nil{token = atokenreturn}// 判断atoken是否为过期类型的错误v,_ := err.(*jwt.ValidationError)if v.Errors == jwt.ValidationErrorExpired{token,err = GetaToken(claims.UserName)err = nil}return
}
// 刷新atoken
func RefreshToken(c *gin.Context){rtoken := c.Query("rtoken")// 验证header中是否有AuthorizationauthHeader := c.GetHeader("Authorization")if authHeader=="" || !strings.HasPrefix(authHeader,"Bearer "){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : "Token不存在",})c.Abort()return}// 解析atokenatoken := authHeader[7:]atoken,err := jwt.RefreshToken(atoken, rtoken)if err!=nil{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : "Token解析失败",})c.Abort()return}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.SUCCES),"atoken" : atoken,})
}

优化

密码加密存储
package encryptimport ("MY-FORUM/config""encoding/base64""fmt""golang.org/x/crypto/scrypt"
)func GenerateSpw(pw string) string {const KeyLen = 22const N = 1 << 10                             // CPU内存成本参数,必须是一个大于1的2的幂const r, p = 8, 1                             // r*p <2^30// salt长度为8比较好npw, err := scrypt.Key([]byte(pw), config.Salt, N, r, p, KeyLen)if err != nil {fmt.Println("密码加密失败", err)}return base64.StdEncoding.EncodeToString(npw) // 获取编码后的字符串
}
func (u *User)BeforeSave(_ *gorm.DB)(err error){u.PassWord = encrypt.GenerateSpw(u.PassWord)return nil
}
雪花算法生成用户ID

社区分类及详情模块

创建数据库

package modelsimport "gorm.io/gorm"type Community struct {gorm.ModelCommunityId int `gorm:"type:int(10)" json:"community_id"`CommunityName string `gorm:"type:varchar(64)" json:"community_name"`Introduction string `gorm:"type:varchar(256)" json:"introduction"`
}
// 模型迁移
db.AutoMigrate(&User{},&Community{})
package modelsimport ("MY-FORUM/utils/errmsg""fmt""time""gorm.io/gorm"
)type Community struct {gorm.ModelCommunityName string `gorm:"type:varchar(64)" json:"community_name" validate:"required"`Introduction  string `gorm:"type:varchar(256)" json:"introduction" validate:"required"`Issure string `gorm:"type:varchar(256)" json:"issure" validate:"required"`
}type CommunityDetail struct {ID            int       `json:"id" db:"id"`CommunityName string    `json:"community_name" db:"community_name"`Introduction  string    `json:"introduction" db:"introduction"`CreatedAt      time.Time `json:"created_at" db:"created_at"`UpdatedAt     time.Time `json:"updated_at" db:"updated_at"`Issure string `json:"issure" db:"issure"`
}// 判断社区是否存在
func FindCommunity(name string) bool {var comm Communityerr := db.Where("community_name = ?", name).First(&comm).Errorif err != nil {fmt.Println("社区查询失败", err)}if comm.ID > 0 {return true}return false
}// 判断id是否存在
func FindCommunityByID(id int)(bool,string){var comm Communityerr := db.Where("id = ?", id).First(&comm).Errorif err != nil {fmt.Println("社区查询失败", err)}if comm.ID > 0 {return true, comm.Issure}return false,""
}// 添加社区
func AddCommunity(comm Community) int {err := db.Create(&comm).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}// 修改社区
func ChangeCommunity(comm Community)int{mp := map[string]interface{}{}mp["Community_name"] = comm.CommunityNamemp["introduction"] = comm.Introductionerr := db.Model(&comm).Updates(mp).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}// 删除社区
func DeleteCommunity(id int)int{var comm Communityerr := db.Where("id = ?", id).Delete(&comm).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}// 查询社区列表(分页)
func GetCommunityList(pagesize, pagenum int)([]Community, int){var commList []Communityerr := db.Select("id", "community_name").Limit(pagesize).Offset((pagenum-1)*pagesize).Find(&commList).Errorif err!=nil{return commList, errmsg.ERROR}return commList, errmsg.SUCCES
}// 查询社区详情
func GetCommunityDetail(id int)(CommunityDetail, int){var comm CommunityDetailerr := db.Model(&Community{}).Where("id = ?",id).First(&comm).Errorif err!=nil{fmt.Println("社区详情查询失败", err)return comm, errmsg.ERROR}return comm, errmsg.SUCCES
}

增加社区类别(鉴权)

// 添加社区
func AddCommunity(c *gin.Context){var community models.Community_ = c.ShouldBind(&community)// 获取中间件的usernameusername := c.GetString("username")community.Issure = username// 参数校验errs := Validate.Struct(community)if errs!=nil{msg := []string{}for _,err := range errs.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : community,})c.Abort()return}// 判断社区是否存在if models.FindCommunity(community.CommunityName){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_EXIST),"data" : community,})c.Abort()return}// 添加社区code := models.AddCommunity(community)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : community,})
}

获取社区分类列表

func GetCommunityList(c *gin.Context){pagesize,_ := strconv.Atoi(c.Query("pagesize"))pagenum,_ := strconv.Atoi(c.Query("pagenum"))if pagesize<=0{pagesize = -1}if pagenum<=1{pagenum = 1}commList, code := models.GetCommunityList(pagesize, pagenum)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : commList,})
}

根据社区ID查找分类详情

// 查询单个社区详情
func GetCommunityDetail(c *gin.Context){id,_ := strconv.Atoi(c.Query("id"))comm, code := models.GetCommunityDetail(id)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : comm,})
}

修改社区(鉴权)

// 修改社区
func ChangeCommunity(c *gin.Context){var community models.Community_ = c.ShouldBind(&community)// 获取中间件的usernameusername := c.GetString("username")community.Issure = username// 参数校验errs := Validate.Struct(community)if errs!=nil{msg := []string{}for _,err := range errs.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : community,})c.Abort()return}// 判断id是否存在flag, issure := models.FindCommunityByID(int(community.ID))if !flag{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_NOT_EXIST),"data" : community,})c.Abort()return}// 判断是否为issureif issure!=c.GetString("username"){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_TRUE),"data" : community,})c.Abort()return}// 判断社区名称是否存在if models.FindCommunity(community.CommunityName){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_EXIST),"data" : community,})c.Abort()return}// 修改社区code := models.ChangeCommunity(community)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : community,})
}

删除社区(鉴权)

// 删除社区
func DeleteCommunity(c *gin.Context){id,_ :=strconv.Atoi(c.Query("id"))// 判断id是否存在flag, issure := models.FindCommunityByID(id)if !flag{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_NOT_EXIST),"data" : id,})c.Abort()return}// 判断是否为issureif issure!=c.GetString("username"){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_TRUE),"data" : id,})c.Abort()return}code := models.DeleteCommunity(id)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : id,})
}

论坛帖子模块

创建数据库

package modelsimport ("MY-FORUM/utils/errmsg""gorm.io/gorm"
)type Post struct {gorm.ModelTitle string `gorm:"type:varchar(64)" json:"title" validate:"required"`Content string `gorm:"type:longtext" json:"content" validate:"required"`AuthorName string `gorm:"type:varchar(64);not null" json:"author_name"`CommunityId int `gorm:"type:bigint;not null" json:"community_id" validate:"required"`Status int `gorm:"type:tinyint(4);default:0" json:"status"`
}// 添加帖子数据
func AddPost(post Post)int{err := db.Create(&post).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}// 分页展示帖子列表
func GetPostList(pagesize, pagenum int)([]Post, int){var posts []Posterr := db.Limit(pagesize).Offset((pagenum-1)*pagesize).Find(&posts).Errorif err!=nil{return posts, errmsg.ERROR}return posts, errmsg.SUCCES
}// 获取帖子详情
func GetPostDetail(id int)(Post, int){var post Posterr := db.Where("id = ?", id).First(&post).Errorif err!=nil{return post, errmsg.ERROR}return post, errmsg.SUCCES
}// 修改帖子
func ChangePost(post Post)int{mp := map[string]interface{}{}mp["title"] = post.Titlemp["content"] = post.Contentmp["community_id"] = post.CommunityIdmp["status"] = post.Statuserr := db.Model(&Post{}).Where("id = ?", post.ID).Updates(mp).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}// 删除帖子
func DeletePost(id int)int{var post Posterr := db.Where("id = ?", id).Delete(&post).Errorif err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}
// 模型迁移db.AutoMigrate(&User{},&Community{},&Post{})

创建帖子

func AddPost(c *gin.Context){var post models.Post_ = c.ShouldBind(&post)post.AuthorName = c.GetString("username")// 进行参数校验err := Validate.Struct(post)if err!=nil{msg := []string{}for _,err := range err.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : post,})c.Abort()return}// 判断社区是否存在if flag,_ :=models.FindCommunityByID(post.CommunityId);!flag{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_NOT_EXIST),"data" : post,})c.Abort()return}// 创建帖子code := models.AddPost(post)if code!=errmsg.SUCCES{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : post,})c.Abort()return}// redis创建帖子code = redis.CreatePost(int(post.ID), post.CommunityId, post.Title, post.Content, post.AuthorName)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : post,})
}

分页展示帖子列表

func GetPostList(c *gin.Context){pagesize,_ := strconv.Atoi(c.Query("pagesize"))pagenum,_ := strconv.Atoi(c.Query("pagenum"))if pagesize <= 0{pagesize = -1}if pagenum < 1{pagenum = 1}posts, code := models.GetPostList(pagesize, pagenum)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : posts,})
}

获取帖子详情

func GetPostDetail(c *gin.Context){id,_ :=strconv.Atoi(c.Query("post_id"))_,code := models.GetPostDetail(id)if code==errmsg.ERROR{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.POST_IS_NOT_EXIST),})c.Abort()return}post, code := models.GetPostDetail(id)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : post,})
}

修改帖子

func ChangePost(c *gin.Context){var post models.Post_ = c.ShouldBind(&post)// 进行参数校验err := Validate.Struct(post)if err!=nil{msg := []string{}for _,err := range err.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : post,})c.Abort()return}// 判断帖子是否存在findPost,code := models.GetPostDetail(int(post.ID))if code==errmsg.ERROR{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.POST_IS_NOT_EXIST),"data" : post,})c.Abort()return}// 判断是否为自己的帖子if findPost.AuthorName != c.GetString("username"){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_TRUE),"data" : post,})c.Abort()return}// 判断社区是否存在if flag,_ :=models.FindCommunityByID(post.CommunityId);!flag{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.COMMUNITY_IS_NOT_EXIST),"data" : post,})c.Abort()return}// 修改帖子内容code = models.ChangePost(post)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : post,})
}

删除帖子

func DeletePost(c *gin.Context){id,_ := strconv.Atoi(c.Query("post_id"))// 判断帖子是否存在findPost,code := models.GetPostDetail(id)if code==errmsg.ERROR{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.POST_IS_NOT_EXIST),"post_id" : id,})c.Abort()return}// 判断是否为自己的帖子if findPost.AuthorName != c.GetString("username"){c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.USER_NOT_TRUE),"data" : findPost,})c.Abort()return}// 删除帖子code = models.DeletePost(id)c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(code),"data" : findPost,})
}

按照时间or分数排序展示帖子列表

全部帖子
某一社区帖子

优化

redis缓存帖子列表
redis mysql 数据一致性

投票模块

redis数据库

package redisimport ("MY-FORUM/config""fmt""github.com/go-redis/redis"
)var (client *redis.Client
)func init(){client = redis.NewClient(&redis.Options{Addr : config.RedisHost+":"+config.RedisPort,Password : "",DB : 0,PoolSize:8,MinIdleConns:1,})_,err :=client.Ping().Result()if err!=nil{fmt.Println("redis连接失败", err)}
}func Close(){_ = client.Close()
}

在redis中添加帖子相关信息

// redis存储帖子信息
func CreatePost(postid, community int, title, content, author_name string) int {now := time.Now().Unix()votedKey := PostVotedZSet+strconv.Itoa(postid)communityKey := CommunityPostSet+strconv.Itoa(community)// 事务操作// 创建一个事务管道pipeline := client.TxPipeline()// 设置投票过期时间pipeline.Expire(votedKey, time.Second*OneWekSecond)// 添加帖子时间排序pipeline.ZAdd(PostTimeZSet, redis.Z{Score: float64(now),Member: postid,})// 添加帖子分数排序pipeline.ZAdd(PostScoreZSet, redis.Z{Score: float64(0),Member: postid,})// 添加到对应的社区pipeline.SAdd(communityKey, postid)// 执行管道中所有命令_, err := pipeline.Exec()if err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}

为帖子投票

func PostVoteHandler(c *gin.Context) {var item PostVote_ = c.ShouldBind(&item)// 进行参数校验errs := Validate.Struct(item)if errs!=nil{msg := []string{}for _,err := range errs.(validator.ValidationErrors){msg = append(msg, err.Translate(Trans))}c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.ERROR),"msg" : msg,"data" : item,})c.Abort()return}// 判断帖子是否存在post_id,_ := strconv.Atoi(item.PostId)_,code := models.GetPostDetail(post_id)if code==errmsg.ERROR{c.JSON(http.StatusOK, gin.H{"status" : errmsg.GetErrMsg(errmsg.POST_IS_NOT_EXIST),"data" : item,})c.Abort()return}// 进行投票code = redis.VoteForPost(c.GetString("username"), item.PostId, float64(item.Direction))c.JSON(http.StatusOK, gin.H{"status": errmsg.GetErrMsg(code),"data": item,})
}
// 为帖子投票
func VoteForPost(username, postid string, v float64)int {// 判断现在是否还在投票期// 获取帖子发布日期postTime := client.ZScore(PostTimeZSet, string(postid)).Val()if float64(time.Now().Unix()-int64(postTime))>OneWekSecond{return errmsg.POST_VOTE_IS_EXPIRE}key := PostVotedZSet+postid// 查看当前用户给帖子的投票记录ov := client.ZScore(key, username).Val()// 判断是否重复投票if ov==v{return errmsg.POST_USER_VOTED}// 计算两次投票的差值diff := v-ov// 创建一个事务管道pipeline := client.TxPipeline()// 更新帖子分数pipeline.ZIncrBy(PostScoreZSet, VoteScore*diff, postid)// 更新用户投票记录pipeline.ZRem(key, username)pipeline.ZAdd(key, redis.Z{Score: v,Member: username,})_,err := pipeline.Exec()if err!=nil{return errmsg.ERROR}return errmsg.SUCCES
}

优化

利用Reddit算法计算帖子排名分数

评论模块

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com