发布帖子功能与查询帖子不同,需要发送POST请求,也就需要在Server中绑定一个POST方法,同时还需要底层提供添加帖子的API以供调用。至于本地id的唯一性,可以简单的维护一个id最大值,每次新的id加一即可。最后需要注意Map的并发安全问题
现有版本基于内存的存储,因此本次课后实践依旧在此基础上进行,所以在现有版本基础上进行课后实践的开发工作
-
系统开始运行查询某个topic下的帖子列表:这个是已经提供的功能,需要注意的是topic和post数据是在系统启动的时候初始化的,查询某个topic的帖子就是直接从map中取出对应topic_id的post列表
var( topicIndexMap map[int64]*Topic postIndexMap map[int64][]*Post ) func (*TopicDao) QueryTopicById(id int64) *Topic { return topicIndexMap[id] } 复制代码 -
为某个topic发布帖子:首先需要提供一个外部的接口,用于发布帖子
r.POST( "/ community/post/pull", func(c *gin.Context) { postInfo := repository.Post{} if C.BindJSON(&postInfo) == nil { data := cotroller.(postInfo) C.JSON(200,data) } }) err := r.Run() iferr != nil{ return } 复制代码 -
repository层
实现要求
//实现一:发布帖子 func ( postDao *PostDao) AddPost(postInfo Post) error { //实现二:本地id生成需要保证不重复、唯一性 postDao.lock.Lock() defer postDao.lock.Unlock() num := int64(0) for _, list := range postIndexMap { num += int64(len(list)) } postInfo.Id= num + 1 postInfo.CreateTime = time.Now().Unix() //实现三:新的帖子Append到文件末尾,更新索引,注意Map的并发安全性问题 filePath := ”./data/post" file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0666) iferr!=nil{ fmt.Println("文件存储失败",err) } defer file.Close() write := bufio.NewWriter(file) data, err := json.Marshal(postInfo) iferr!=nil{ return err } write.WriteString(string(data) + "\r\n") write.Flush() post IndexMap[postInfo.ParentId] = append(postIndexMap[postInfo.ParentId], &postInfo) return nil } 复制代码
- 因为postIndexMap[topic_id]对应着这个主题的所有帖子,但是数据是系统启动时去文件中读取的,在我们为文件追加一条post之后,并不会自动更新这个list,因此需要我们手动去追加帖子数据到postIndexMap[topic_id]末尾,才能做到内存数据与文件数据的一致性保证,从而不重启系统,重新获取列表就能查询到最新的帖子列表。因此不重启系统的情况下再次查询该topic的帖子列表需要更新
- 这里提到的文件追加和map追加都涉及到并发安全性的问题,这里使用了互斥锁。
- 关于自增id这里因为可以保证临界区的互斥访问,因此采用计数累加的形式实现帖子id唯一性