帖子详情
这个比较简单了,之前做过多次。
注册路由:
v1.GET("/post/:id", controllers.GetPostDetailHandler)
复制代码
controller:
// 获取帖子详情
func GetPostDetailHandler(c *gin.Context) {
postIdStr := c.Param("id")
postId, err := strconv.ParseInt(postIdStr, 10, 64)
// 校验参数是否正确
if err != nil {
zap.L().Error("GetPostDetailHandler", zap.Error(err))
ResponseError(c, CodeInvalidParam)
return
}
data, err := logic.GetPostDetail(postId)
if err != nil {
zap.L().Error("GetPostDetailHandler", zap.Error(err))
ResponseError(c, CodeServerBusy)
return
}
ResponseSuccess(c, data)
}
复制代码
logic
func GetPostDetail(id int64) (model *models.Post, err error) {
return mysql.GetPostDetail(id)
}
复制代码
dao:
func GetPostDetail(id int64) (post *models.Post, err error) {
post = new(models.Post)
sqlStr := "select post_id,title,content,author_id,community_id,create_time,update_time " +
" from post where post_id=?"
err = db.Get(post, sqlStr, id)
if err != nil {
// 空数据的时候 不算错误 只是没有板块而已
if err == sql.ErrNoRows {
zap.L().Warn("no community ")
err = nil
}
}
return post, err
}
复制代码
看下效果
优化帖子详情接口
上述的帖子接口其实还有些问题 主要是 返回的数据里面只有 作者id和板块id 这样的可读性太差
我们来稍微修改一下即可
新增一个结构体:
type ApiPostDetail struct {
AuthorName string `json:"author_name"`
*Community `json:"_community"`
*Post `json:"_post"`
}
复制代码
再改下我们的logic 就合乎要求了:
func GetPostDetail(id int64) (apiPostDetail *models.ApiPostDetail, err error) {
//先查帖子实体
post, err := mysql.GetPostDetail(id)
//再查 作者 名称
username, err := mysql.GetUserNameById(post.AuthorId)
if err != nil {
zap.L().Warn("no author ")
err = nil
}
//再查板块实体
community, err := GetCommunityById(post.CommunityId)
if err != nil {
zap.L().Warn("no community ")
err = nil
}
apiPostDetail = new(models.ApiPostDetail)
apiPostDetail.AuthorName = username
apiPostDetail.Community = community
apiPostDetail.Post = post
return apiPostDetail, err
}
复制代码
分页展示帖子列表
分页查询其实也不难,主要就是sql 语句那边稍微改一下,然后logic层多了一个for 循环来拼接我们的查询结果
v1.GET("/postlist", controllers.GetPostListHandler)
复制代码
func GetPostListHandler(c *gin.Context) {
pageSizeStr := c.Query("pageSize")
pageNumStr := c.Query("pageNum")
pageSize, err := strconv.ParseInt(pageSizeStr, 10, 64)
if err != nil {
ResponseError(c, CodeInvalidParam)
return
}
pageNum, err := strconv.ParseInt(pageNumStr, 10, 64)
if err != nil {
ResponseError(c, CodeInvalidParam)
return
}
if pageNum < 1 {
ResponseErrorWithMsg(c, CodeInvalidParam, "页码不可小于1")
return
}
data, err := logic.GetPostList(pageSize, pageNum)
if err != nil {
zap.L().Error("GetPostDetailHandler", zap.Error(err))
ResponseError(c, CodeServerBusy)
return
}
ResponseSuccess(c, data)
}
复制代码
func GetPostList(pageSize int64, pageNum int64) (apiPostDetailList []*models.ApiPostDetail, err error) {
var offset int64
offset = pageSize * (pageNum - 1)
postList, err := mysql.GetPostList(offset, pageSize)
if err != nil {
return nil, err
}
apiPostDetailList = make([]*models.ApiPostDetail, 0, 2)
for _, post := range postList {
//再查 作者 名称
username, err := mysql.GetUserNameById(post.AuthorId)
if err != nil {
zap.L().Warn("no author ")
err = nil
return nil, err
}
//再查板块实体
community, err := GetCommunityById(post.CommunityId)
if err != nil {
zap.L().Warn("no community ")
err = nil
return nil, err
}
apiPostDetail := new(models.ApiPostDetail)
apiPostDetail.AuthorName = username
apiPostDetail.Community = community
apiPostDetail.Post = post
apiPostDetailList = append(apiPostDetailList, apiPostDetail)
}
return apiPostDetailList, nil
}
复制代码
func GetPostList(offset int64, pageSize int64) (posts []*models.Post, err error) {
zap.L().Info("GetPostList", zap.String("offset", strconv.FormatInt(offset, 10)), zap.String("pageSize", strconv.FormatInt(pageSize, 10)))
sqlStr := "select post_id,title,content,author_id,community_id,create_time,update_time " +
" from post limit ?,?"
posts = make([]*models.Post, 0, pageSize)
err = db.Select(&posts, sqlStr, offset, pageSize)
if err != nil {
return nil, err
}
return posts, err
}
复制代码
前端id 失真
上述的代码 我们都是用雪花算法 来生成 一个int64的 id,并且在json中 我们返回的是一个数字 并不是一个字符串 这会导致一个问题,在go语言中 int64的最大值如下:
max: 9223372036854775807
然而前端的类型中 将数字 视为 number类型 最大值是2的53次方 9007199254740992
明显这个int64 比这个值要大
实际中 前端在拿到这个数字 解析出来就会出现精度丢失的问题了。
所以 通常而言,作为服务端 对于id类型的 我们还是在json中返回成字符串比较好。
同样的 前端在给我们传递值也一样最好约定成字符串 ,这样服务端拿到值以后 自己做相应的转换是最保险的
在go语言中
我们只要在设置tag的地方 标识一下string就可以了
当然你也可以对你的struct来定义 序列化和反序列化的方法,也可以解决这个问题。但是显然效率是不如这个tag的写法的