第二次作业——《Go 语言上手-工程实践》

72 阅读1分钟

课后作业:

1. 支持发布帖子

2. 本地 ID 生成需要保证不重复、唯一性

3. Append 文件,更新索引,注意 Map 的并发安全问题

思路:采用json文件代替mysql来存储topic的键值对。

项目结构如下图

image.png

1.支持发布帖子

1.1 main.go中新增路由"community/topic/add"

r.POST("/community/topic/add", func(c *gin.Context) {
   userId, _ := c.GetPostForm("user_id")
   title, _ := c.GetPostForm("title")
   content, _ := c.GetPostForm("content")
   data := controller.AddTopic(userId, title, content)
   c.JSON(200, data)
})

1.2 controller层中的AddTopic函数处理

func AddTopic(userIdStr, title, content string) *PageData {
   //参数转换
   userId, _ := strconv.ParseInt(userIdStr, 10, 64)
   //获取service层结果
   topicId, err := service.AddTopic(userId, title, content)
   if err != nil {
      return &PageData{
         Code: -1,
         Msg:  err.Error(),
      }
   }
   return &PageData{
      Code: 0,
      Msg:  "发帖成功",
      Data: map[string]int64{
         "topic_id": topicId,
      },
   }
}

1.3 service层封装数据

func (f *AddTopicFlow) add() error {
   topic := &repository.Topic{
      Id:         getOnlyId(),
      UserId:     f.userId,
      Title:      f.title,
      Content:    f.content,
      CreateTime: time.Now(),
   }
   if err := repository.NewTopicDaoInstance().AddTopic(topic); err != nil {
      return err
   }
   f.topicId = topic.Id
   return nil
}

1.4 repository层将数据写入文件

func (*TopicDao) AddTopic(topic *Topic) error {
   var topics = make([]Topic, 1)
   file, err := ioutil.ReadFile("./json/topic.json")
   if err != nil {
      println("read file failed", err)
      return err
   }

   var jsonErr error
   if len(file) == 0 {
      jsonErr = nil
   } else {
      jsonErr = json.Unmarshal(file, &topics)
   }
   if jsonErr == nil {
      topics = append(topics, *topic)
      data, err := json.MarshalIndent(topics, "", " ")
      if err == nil {
         err := ioutil.WriteFile("./json/topic.json", data, 0666)
         if err == nil {
            println("写入成功")
            return nil
         }
      }
   }
   println("写入失败")
   return err
}

1.5 运行结果

postman中返回结果

image.png

topic.json文件中的数据

image.png

2.保证id生成的唯一性:采用雪花算法来生成唯一的id

import "github.com/bwmarrin/snowflake"
func getOnlyId() int64 {
   node, err := snowflake.NewNode(1)
   if err != nil {
      print("get id failed")
      return -1
   }
   id := node.Generate()
   return int64(id)
}

3.并发安全问题:使用读写锁来完成

3.1 在读文件的时候加锁,读完文件再解锁

rwLock.Lock()
file, err := ioutil.ReadFile("./json/topic.json")
rwLock.Unlock()

3.2 在写文件的时候加锁,写完文件再解锁

rwLock.Lock()
err := ioutil.WriteFile("./json/topic.json", data, 0666)
rwLock.Unlock()