这是我参与「第五届青训营 」笔记创作活动的第二天,在本日的学习中,简单了解了一些GO编程的工程基础。下面将基于上课的代码,简单修改完成课后实践题。
具体过程
首先我们分析一下Post的格式:
type Post struct {
Id int64 `json:"id"`
ParentId int64 `json:"parent_id"`
Content string `json:"content"`
CreateTime int64 `json:"create_time"`
}
可以发现,Id是自增长的,ParentId是基于当前话题页的,Content是用户输入的,而CreateTime则应该基于当前时间。也就是说,Id和CreateTime应该由程序自动填充,而另外两个则要基于前端的Post请求参数。
为此,我们简单实现一个处理Post请求的路由:
r.POST("/community/page/post/:id", func(c *gin.Context) {
// 数据处理部分:
content := c.PostForm("content")
create_time := time.Now().Unix()
parent_id, err := strconv.ParseInt(c.Param("id"), 10, 64)
id := 1145 //暂时如此
// 暂不处理错误路由部分
if err != nil {
fmt.Println("请求路径有误")
return
}
newPost := repository.Post{Id: int64(id), ParentId: parent_id, Content: content, CreateTime: create_time}
//先测试传输是否正确
fmt.Println(newPost)
})
然后可以用curl命令模拟前端接收的Post请求:
curl -X POST -d "content=just_a_test" "http://127.0.0.1:8080/community/page/post/2"
得到结果接收正确:
然后实现一下将新数据加入map和文件的数据层函数:
func AddPostIndexMap(filePath string, newInfo *Post) error {
open, err := os.OpenFile(filePath+"post", os.O_APPEND|os.O_RDWR, 0660)
if err != nil {
return err
}
defer open.Close()
// 使用最简单的锁保证并发安全
lock.Lock()
posts, ok := postIndexMap[newInfo.ParentId]
if !ok {
postIndexMap[newInfo.ParentId] = []*Post{newInfo}
} else {
posts = append(posts, newInfo)
postIndexMap[newInfo.ParentId] = posts
}
json_string, err := json.Marshal(newInfo)
if err != nil {
return err
}
open.WriteString("\n" + string(json_string))
lock.Unlock()
return nil
}
在上面的代码中,加入map操作可以类比原有的initPostIndexMap函数,而写入文件则可以考虑直接使用WriteString函数。整体的并发安全只使用了最简单的锁,显然该做法是简单粗暴且较为费时的,后续会考虑改进。
再写一个简单的服务层函数用于调用上面的函数,在视图层调用即可:
func AddPostInfo(filePath string, newInfo *repository.Post) {
go repository.AddPostIndexMap(filePath, newInfo)
}
最后,我们还剩下回帖ID的唯一自增。可以考虑在数据层加入一个计数器用于记录当前到第几条回帖信息,并在初始化时顺便初始化计数器即可。
测试并发性,这里采用最简单的串行测试,仅仅使用批处理命令循环发送post请求,可以得到正确的结果:
for /l %%i in (1,1,100) do (
curl -X POST -d "content=just_a_test" "http://127.0.0.1:8080/community/page/post/2"
)