使用 Gin 开发微服务课堂练习(一)

本实验手册旨在帮助学员使用 Gin 框架来开发微服务。 Gin 是 Go 语言生态环境中比较出名的 Web 框架,具有简单,高性能,开源等特点。

在第一次练习中,我们首先搭建好项目框架,然后实现一个简单的 rest 服务。

建立项目

新建一个名为: go-todo-api-srv 的目录,用来存放所有项目相关的文件。

1
mkdir go-todo-api-srv

进入该目录

1
cd go-todo-api-srv

因为我们使用 go modules 来管理依赖,因此首先初始化模块,执行:

1
go mod init go-todo-api-srv

如果正常,系统会在目录中新建一个名为: go.mod 的文件,内容如下:

1
2
3
module go-todo-api-srv

go 1.14

第一行是我们命名的模块名,第三行是当前项目使用的 go 的版本。

在项目中引用 Gin 库

为了在项目中引用 Gin 库,我们可以使用 go get 命令, 执行:

1
go get github.com/gin-gonic/gin

如果正常,系统显示:

1
go: github.com/gin-gonic/gin upgrade => v1.6.2

写本文时 Gin 的最新版本为 1.6.2

查看 go.mod 文件,会看到文件的末尾加上了对 gin 库依赖的声明:

1
2
3
4
5
module go-todo-api-srv

go 1.14

require github.com/gin-gonic/gin v1.6.2 // indirect

同时,我们可以看到在项目中多生成了一个名为: go.sum 的文件,里面包含了具体的依赖库的声明及间接依赖库声明,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM=
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

建立实体类型

在 Go 语言中,没有在其它语言(比如: Java, C#等)中的类,因此为表现一个业务实体的数据我们使用结构类型。为方便以后扩展,我们将所有的业务实体类型放在 entity 目录中。

在项目目录中新建 entity 目录

1
mkdir entity

在 entity 目录中新建名为: Todo.go 的文件, 内容如下:

1
2
3
4
5
6
7
8
9
package entity

// Todo is the entity bean to store some status for a action
type Todo struct {
ID uint `json:"id"`
Title string `json:"title"`
Desc string `json:"desc"`
Done bool `json:"done"`
}

建立启动程序

在项目目录中新建名为: main.go 的文件,建立后,整个项目的文件和目录包括:

1
2
3
4
5
6
go-todo-api-srv/
+ entity
Todo.go
main.go
go.mod
go.sum

在 main.go 中引入对 gin 和自建 entity 的引用:

1
2
3
4
import (
"github.com/gin-gonic/gin"
"go-todo-api-srv/entity"
)

注意:在引入自定义的entity包时,需要使用模块名加上包名

因为在第一次练习中,还没有引入数据库,因此先直接声明一个数组来模拟服务返回的数据:

1
2
3
var todos = []entity.Todo {
entity.Todo{ID: 1, Title: "call tom", Desc: "desc of todo 1", Done: false},
}

最后,新建 main 函数,启动服务:

1
2
3
4
5
6
7
8
9
10
func main() {
r := gin.Default()

r.GET("/api/todo", func(c *gin.Context) {
c.JSON(http.StatusOK, todos)
})

r.Run()

}

可以看到,我们使用 Gin 的路由功能建立了一个路由, 路径是: “/api/todo”。 当用户访问该路径时,对应的函数将被执行,当前只是简单的以JSON形式返回数据。

完整的 main.go 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"net/http"
"github.com/gin-gonic/gin"
"go-todo-api-srv/entity"
)

var todos = []entity.Todo {
entity.Todo{ID: 1, Title: "call tom", Desc: "desc of todo 1", Done: false},
}

func main() {
r := gin.Default()

r.GET("/api/todo", func(c *gin.Context) {
c.JSON(http.StatusOK, todos)
})

r.Run()

}

运行项目

在项目目录中执行:

1
go run main.go

如果正常,可以看到如下的系统输出:

1
2
3
4
5
6
7
8
9
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET /api/todo --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

可以看到,服务已经启动并在本地的 8080 端口进行监听。

打开浏览器,访问:

1
http://localhost:8080/api/todo

可以在浏览器中看到如下内容:

1
2
3
4
5
6
7
8
[
{
"id": 1,
"title": "call tom",
"desc": "desc of todo 1",
"done": false
}
]

本文标题:使用 Gin 开发微服务课堂练习(一)

文章作者:梅老师

发布时间:2020年04月04日 - 15:04

最后更新:2020年09月16日 - 08:09

原始链接:https://www.mls-tech.info/golang/go-gin-rest-practice-manual-01/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。