GO语言工程实践| 青训营笔记

68 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

课堂笔记

本堂课重点内容

  • 第三方框架
  • 小功能设计
  • 功能设计路线

详细知识点介绍

需求设计

需求背景

  • 支持回帖、点赞
  • 对回帖可以进行回复
  • 开发一个单页面设计服务端的小功能

需求描述

社区话题页面

  • 展示话题(标题,文字描述)和回帖列表
  • 暂不考虑前端页面实现,仅仅实现一个本地web服务
  • 话题和回帖数据用文件存储

需求用例

面向浏览消费用户

  • Topic -> 话题
  • PostList -> 回帖历史

E-R

  • Topic<话题>

    • id
    • title
    • content
    • create_time
  • Post<帖子>

    • id
    • topic_id
    • content
    • create_time

Topic和Post的关系是一对多

分层结构

  • 数据层Repostitory

    • 数据Model,外部数据的增删改查
  • 逻辑层Service

    • 业务Entity,处理核心业务逻辑输出
  • 视图层Controller

    • 视图view,处理和外部的交互逻辑

组件工具

Gin高性能go web框架

github.com/gin-gonic/g…

Go Mod

go mod init

go get gopkg.in/gin-gonic/gin.v1@v1.3.0

代码开发

Repository

index

元数据 -> 索引

数据行 -> 内存map

 var (
     topicIndexMap map[int64]*Topic
     postIndexMap  map[int64]*Post
 )

初始化话题数据索引

 func initTopicIndexMap(filePath string) error {
     open, err := os.Open(filePath + "topic")
     if err != nil {
         return err
     }
     scanner := bufio.NewScanner(open)
     topicTmpMap := make(map[int64]*Topic)
     for scanner.Scan() {
         text := scanner.Text()
         var topic Topic
         if err := json.Unmarshal([]byte(text), &topic); err != nil {
             return err
         }
         topicTmpMap[topic.Id] = &topic
     }
     topicIndexMap = topicTmpMap
     return nil
 }
 ​
查询

索引:话题ID

数据:话题

使用symc.Once来实现高并发状态下只查询一次

 var (
     topicOnce sync.Once //高并发下只执行一次
     topicDao  *TopicDao
 )
 ​
 func NewTopicDaoInstance() *TopicDao {
     topicOnce.Do(func() {
         topicDao = &TopicDao{}
     })
     return topicDao
 }
 func (*TopicDao) QueryTopicDyId(id int64) *Topic {
     return topicIndexMap[id]
 }
 ​
 var (
     topicIndexMap map[int64]*Topic
     postIndexMap  map[int64]*Post
 )

Service

实体
 type TopicDao struct {
     Topic    *repository.Topic
     PostList []*repository.Post
 }
流程

参数校验

准备数据

组装实体

 func (f *QueryPageInfoFlow) Do() (*PageInfo, error) {
     if err := f.checkParam(); err != nil {
         return nil, err
     }
     if err := f.prepareInfo(); err != nil {
         return nil, err
     }
     if err := f.packPageInfo(); err != nil {
         return nil, err
     }
     return f.pageInfo, nil
 }

Controller

 func QueryPageInfo(topicIdStr string) *PageData {
     topicId, err := strconv.ParseInt(topicIdStr, 10, 64)
     if err != nil {
         return &PageData{}
     }
     pageInfo, err := service.QueryPageInfo(topicId)
     if err != nil {
         return &PageData{}
     }
     return &PageData{}
 }

Router

  • 初始化数据索引
  • 初始化引擎配置
  • 构建路由
  • 启动服务
 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)
     })
     err := r.Run()
     if err != nil {
         return
     }
 }

实践练习例子

课后个人总结

  • 需要熟练引用第三方的包来进行构建
  • 搭建某个功能最好是采用第三方框架入手