第二次课实践作业记录 | 青训营笔记

111 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记,主要内容是对第二节课的课后实践作业做一次记录。

课后实践

img.png 帖子 需要知道的信息有 主题(parentId),回复内容(content),创建时间(create_time),根据已有map自动建立索引并且需要注意并发安全

repository层

思路:每增加一个帖子,需要在post文件中增加一条记录,同时要考虑到并发安全,和帖子id的唯一性。那么首先考虑在数据层增加一个原子读操作GetPostId(), 该方法打开文件post,并读取其中的所有帖子记录,并返回下一条帖子的ID(可以理解为统计已发帖子个数)。

同时需要新增一个 AddPostByParentId(post Post)函数,函数功能是对post文件进行写入,并更新map,具体代码如下

func (*PostDao) AddPostByParentId(post Post) error {
   //写入文件
   lock.Lock()
   defer lock.Unlock()
   file, err := os.OpenFile("E:\ByteDance\goProjectExample\data\post", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
   if err != nil {
      return err
   }
   defer file.Close()

   data, err := json.Marshal(post)
   data = append(data, '\n')
   if err != nil {
      return err
   }
   file.Write(data)
   //更新map postIndexMap  map[int64][]*Post
   postIndexMap[post.ParentId] = append(postIndexMap[post.ParentId], &post)

   return nil
}

AddPostByParentId(post Post)函数的知识点涉及到文件读写,JSON格式转换和锁的使用,在写文件之前上锁,禁止一切的其他的读写,确保帖子的ID的唯一性,并更新map。

service层

在service层中新增了一个AddPost的方法,其具体形式为func AddPost(topicId int64, content string, creatTime int64) error,函数参数接收通过controller层传来的 主题ID,发帖内容和创建时间,并将其封装为repository层中的Post结构体,并调用repository层中的GetPostId()AddPostByParentId(post Post),本来还 应该在这个函数中写一些更复杂的逻辑判断,比如传入的topicID是否存在该主题的讨论区,(最开始的parentId只有1和2,如果传入为3则不合法),但为了简单只先确保了 整个数据是通的。

func AddPost(topicId int64, content string, creatTime int64) error {
   Dao := repository.PostDao{}
   id, err := Dao.GetPostId()
   if err != nil {
      return err
   }
   //这里应该还有一些逻辑检查 判断回帖的信息是否合法
   Dao.AddPostByParentId(repository.Post{
      Id:         id,
      ParentId:   topicId,
      Content:    content,
      CreateTime: creatTime,
   })
   return nil
}

controller层

控制器层主要是对前端传入的表单数据做一下格式上的转换,并将转换后的数据传给service层的AddPost()方法

func AddNewPost(topicIdStr, content, create_time string) int {
   topicId, err := strconv.ParseInt(topicIdStr, 10, 64)
   if err != nil {
      return -1
   }
   creatTime, err := strconv.ParseInt(create_time, 10, 64)
   if err != nil {
      return -1
   }
   err = service.AddPost(topicId, content, creatTime)
   if err != nil {
      return -1
   }
   return 200
}

server.go

在主服务中主要学习的知识点是有关gin框架的使用,利用POST方法从表单中获取传入的数据,涉及到的知识点有RESTful风格,Gin框架的使用

func main() {
   if err := Init("./data/"); err != nil {
      os.Exit(-1)
   }
   r := gin.Default()
   r.GET("/community/page/get/:id", func(c *gin.Context) {
      topicId := c.Param("id")
      data := cotroller.QueryPageInfo(topicId)
      c.JSON(200, data)
   })
   //发布回帖功能
   r.POST("/community/page/post/:id", func(c *gin.Context) {
      topicId := c.Param("id") //主题id
      content, ok := c.GetPostForm("content")
      if !ok {
         c.JSON(-1, "获取帖子内容失败")
      }
      create_time, ok := c.GetPostForm("creatTime")
      if !ok {
         c.JSON(-1, "获取帖子发布时间失败")
      }
      //c.JSON(200, gin.H{"帖子主题": topicId, "内容": content, "发布时间": create_time})
      status := cotroller.AddNewPost(topicId, content, create_time)
      c.JSON(status, gin.H{"发布状态": status})
   })
   err := r.Run()
   if err != nil {
      return
   }
}

测试过程

在写每一层函数的时候,都最好写一个关于自己写的函数的test方法,这样能第一时间发现错误,而不是在整个三层的代码写完以后再来测试。每一步的测试,可以自己设计数据,运行后观察数据是否被写入 post文件中。 最后运行服务器,使用postman等工具进行测试。运行结果如下:

首次查询主题1

img_1.png

发帖

img_2.png

查看本地文件是否新增记录

img_3.png 再次使用get方法查询

img_4.png

通过测试可以得出后端的数据通路已经是通畅的,之后我重新选择不同主题插入数据,可以发现本地文件中帖子id的信息是唯一的

img_5.png 高并发的测试后续学习以后再继续完善。

小结

这一次的实践内容让我自己记忆深刻的几个知识点是:

1.网络编程restful风格与gin框架的结合
2.Go语言文件读写操作
3.Go语言锁的运用

但自己写的代码我觉得还是不够规范,之后要阅读更多的资料,了解更多关于并发上的一些规则和方法。