gin快速开始| 青训营笔记

84 阅读3分钟

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

是什么

Gin 是一个用 Go (Golang) 编写的 web 框架。它是一个类似于 martini 但拥有更好性能的 API 框架,由于  httprouter,速度提高了近 40 倍。如果你是性能和高效的追求者,你会爱上 Gin!

下载gin

手动拉取:
在cmd中输入下载语句
go get github.com/gin-gonic/gin

自动拉取:
使用golang进行开发时,在go.mod文件中添加依赖,并在设置中启用模块集成,ide会自动把我们拉取依赖

image.png

运行原理

MVC(Model View Controller)模型

  • 模型(Model):负责存储系统的中心数据
  • 视图(View):将信息显示给用户(可以定义多个视图)
  • 控制器(Controller):处理用户输入的信息。负责从视图读取数据,控制用户输入,并向模型发送数据,是应用程序中处理用户交互的部分。负责管理与用户交互交互控制

image.png

编写repository层代码

持久层数据本次案例采用json数据进行模拟,例子:

{"id":1,"parent_id":1,"content":"小姐姐快来1","create_time":1650437616}
{"id":2,"parent_id":1,"content":"小姐姐快来2","create_time":1650437617}
{"id":3,"parent_id":1,"content":"小姐姐快来3","create_time":1650437618}
{"id":4,"parent_id":1,"content":"小姐姐快来4","create_time":1650437619}
{"id":5,"parent_id":1,"content":"小姐姐快来5","create_time":1650437620}
{"id":6,"parent_id":2,"content":"小哥哥快来1","create_time":1650437621}
{"id":7,"parent_id":2,"content":"小哥哥快来2","create_time":1650437622}
{"id":8,"parent_id":2,"content":"小哥哥快来3","create_time":1650437623}
{"id":9,"parent_id":2,"content":"小哥哥快来4","create_time":1650437624}
{"id":10,"parent_id":2,"content":"小哥哥快来5","create_time":1650437625}

在持久层的代码中导入初始化数据:

func Init(filePath string) error {
   if err := initTopicIndexMap(filePath); err != nil {
      return err
   }
   if err := initPostIndexMap(filePath); err != nil {
      return err
   }
   return nil
}

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
}

func initPostIndexMap(filePath string) error {
   open, err := os.Open(filePath + "post")
   if err != nil {
      return err
   }
   scanner := bufio.NewScanner(open)
   postTmpMap := make(map[int64][]*Post)
   for scanner.Scan() {
      text := scanner.Text()
      var post Post
      if err := json.Unmarshal([]byte(text), &post); err != nil {
         return err
      }
      posts, ok := postTmpMap[post.ParentId]
      if !ok {
         postTmpMap[post.ParentId] = []*Post{&post}
         continue
      }
      posts = append(posts, &post)
      postTmpMap[post.ParentId] = posts
   }
   postIndexMap = postTmpMap
   return nil
}

编写service层代码

编写具体的业务方法,主要表现为对持久层的数据处理以及其他业务逻辑

package service

import (
   "errors"
   "github.com/Moonlight-Zhao/go-project-example/repository"
   "sync"
)

type PageInfo struct {
   Topic    *repository.Topic
   PostList []*repository.Post
}

func QueryPageInfo(topicId int64) (*PageInfo, error) {
   return NewQueryPageInfoFlow(topicId).Do()
}

func NewQueryPageInfoFlow(topId int64) *QueryPageInfoFlow {
   return &QueryPageInfoFlow{
      topicId: topId,
   }
}

type QueryPageInfoFlow struct {
   topicId  int64
   pageInfo *PageInfo

   topic   *repository.Topic
   posts   []*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
}

func (f *QueryPageInfoFlow) checkParam() error {
   if f.topicId <= 0 {
      return errors.New("topic id must be larger than 0")
   }
   return nil
}

func (f *QueryPageInfoFlow) prepareInfo() error {
   //获取topic信息
   var wg sync.WaitGroup
   wg.Add(2)
   go func() {
      defer wg.Done()
      topic := repository.NewTopicDaoInstance().QueryTopicById(f.topicId)
      f.topic = topic
   }()
   //获取post列表
   go func() {
      defer wg.Done()
      posts := repository.NewPostDaoInstance().QueryPostsByParentId(f.topicId)
      f.posts = posts
   }()
   wg.Wait()
   return nil
}

func (f *QueryPageInfoFlow) packPageInfo() error {
   f.pageInfo = &PageInfo{
      Topic:    f.topic,
      PostList: f.posts,
   }
   return nil
}

编写控制层代码

主要是对业务层代码的调用处理以及返回结果的封装处理

package cotroller

import (
   "github.com/Moonlight-Zhao/go-project-example/service"
   "strconv"
)


func PublishPost(topicIdStr, content string) *PageData {
   //参数转换
   topicId, _ := strconv.ParseInt(topicIdStr, 10, 64)
   //获取service层结果
   postId, err := service.PublishPost(topicId, content)
   if err != nil {
      return &PageData{
         Code: -1,
         Msg:  err.Error(),
      }
   }
   return &PageData{
      Code: 0,
      Msg:  "success",
      Data: map[string]int64{
         "post_id": postId,
      },
   }

}

注册路由

首先调用init方法进行数据初始化,然后注册路由,本例子中注册了一个请求路径为/community/page/get的get请求、注册了一个请求路径为/community/post/do的post请求。
在运行该文件后,会为注册的请求路径绑定一个端口,默认8080端口,此时我们在浏览器输入ip端口+路径就可以访问了。

package main
import (
   "github.com/Moonlight-Zhao/go-project-example/cotroller"
   "github.com/Moonlight-Zhao/go-project-example/repository"
   "gopkg.in/gin-gonic/gin.v1"
   "os"
)

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/post/do", func(c *gin.Context) {
      topicId, _ := c.GetPostForm("topic_id")
      content, _ := c.GetPostForm("content")
      data := cotroller.PublishPost(topicId, content)
      c.JSON(200, data)
   })
   err := r.Run()
   if err != nil {
      return
   }
}

func Init(filePath string) error {
   if err := repository.Init(filePath); err != nil {
      return err
   }
   return nil
}