Go Web框架Gin

1. Gin简介

Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确。具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比PythonJava之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。

2. Gin安装

1
2
3
4
5
6
7
8
9
#创建目录
mkdir gin

#创建mod
cd gin
go mod init gin

#下载gin
go get -u github.com/gin-gonic/gin

3. 案例

3.1 案例一

写一个最简单的gin框架

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

import (
"fmt"
"github.com/gin-gonic/gin"
)

func main() {
//1.创建路由engine
//创建engine,r就是*Engine结构体
r := gin.Default()
//2.路由绑定
//func(c *gin.Context)
r.GET("/", func(c *gin.Context) {
//1.解析get/post请求的参数
//2.根据参数去查询数据库(操作数据库:添加数据、删除数据)
//3.返回从数据库查询的数据
c.String(200, "hello world")
})
fmt.Println("http://127.0.0.1:8000")
//3.启动监听端口
//对net/http服务的封装,替换了http.ListenAndServer(address,engine)
r.Run(":8000")
}

image-20240524212253680

3.2 案例二

写一个最简单的无参路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "github.com/gin-gonic/gin"

func main() {
//生成engine
r := gin.Default()

//无参路由
r.GET("/hello", hello)
r.Run(":8000")
}

// 把hello处理函数拿出来
func hello(c *gin.Context) {
c.String(200, "hello")
}

image-20240524212848558

3.3 案例三

API参数

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

import (
"fmt"
"github.com/gin-gonic/gin"
)

func main() {
//生成engine
r := gin.Default()

//API路由:http://127.0.0.1:8000/product/16
//:id表示使用id来获取16这是值
r.GET("/product/:id", GetProduct)
r.Run(":8000")
}

// 把GetProduct处理函数拿出来
func GetProduct(c *gin.Context) {
//这里c.Param("id")这个id一定要在路由中:id完全一致
ProductId := c.Param("id")
fmt.Println(ProductId, "------")
c.String(200, "API params")
}

image-20240524213914090

3.4 案例四

url参数

url传参: http://127.0.0.1:8000/user?id=20&name=luck

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
package main

import (
"fmt"

"github.com/gin-gonic/gin"
)

func main() {
// 1、生成engine
r := gin.Default()

// url传参: http://127.0.0.1:8000/user?id=20&name=lucky
r.GET("/user", Getuser)

r.Run(":8000")
}

func Getuser(c *gin.Context) {
// 1、获取值,如果没有为 nil
name := c.Query("name")
// 2、获取值,如果没有使用默认值
/*
name : key
default val : 如果没传入参数,就是用默认值
*/
name2 := c.DefaultQuery("name", "default")
fmt.Println("获取的用户名---》", name, name2)
c.String(200, "URL params")
}

image-20240525092624928

3.5 案例五

shouldBind参数绑定

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
package main

import (
"fmt"
"github.com/gin-gonic/gin"
)

func main() {
//生成engine
r := gin.Default()

//shouldBind绑定(解析post请求中复杂的json数据)
r.POST("/login/", logfunc)
r.Run(":8000")
}

type Login struct {
//post请求的数据字段名一定要和`json:"username"`一摸一样
//binding:"required"要求username字段不能为空
Username string `json:"username" binding:"required"`
//Username string `json:"username"`
Password string `json:"password"`
}

// shouldBind方法获取json中复杂数据,并且可以对参数进行校验
func logfunc(c *gin.Context) {
var login Login
//c.ShouldBind(&login)方法必须要传入一个结构体对象
//将net/http中的r.Body数据解析到Login的结构体中
// c.ShouldBind(&login) => json.Unmarshal(bodyContent, &d)
if err := c.ShouldBind(&login); err != nil {
fmt.Println(err)
c.String(200, "参数校验错误")
}
fmt.Println(login.Username, login.Password)
c.String(200, "success")
}

3.6 案例六

响应返回

  1. 响应string字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package main

    import "github.com/gin-gonic/gin"

    func main() {
    r := gin.Default()
    r.GET("/response", responsefunc)
    r.Run(":8000")
    }

    // 响应一个普通的String字符串
    func responsefunc(c *gin.Context) {
    c.String(200, "响应一个string字符串")
    }

    image-20240525102700480

  2. 响应json数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package main

    import "github.com/gin-gonic/gin"

    func main() {
    r := gin.Default()
    r.GET("/response/json", responsefunc)
    r.Run(":8000")
    }

    // 响应一个json数据(最常用)
    func responsefunc(c *gin.Context) {
    c.JSON(200, gin.H{
    "msg": "sucess",
    "code": 1001,
    })
    }

    image-20240525103153850

  3. 路由分发

    一个项目往往有非常多的模块,如果全部写在一起会导致代码结构混乱,不利于后续的扩展

    按照大的模块,每个模块都有自己的路由,主路由可以在main.go中进行注册

    image-20240525113253931

main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"github.com/gin-gonic/gin"
"route/routers"
)

func main() {
r := gin.Default()
routers.Users(r)
routers.Books(r)
r.Run(":8000")
}

bookinfo.go

1
2
3
4
5
6
7
8
9
10
11
package routers

import "github.com/gin-gonic/gin"

func Books(r *gin.Engine) {
r.GET("/book", BooksHandler)
}

func BooksHandler(c *gin.Context) {
c.String(200, "书籍模块")
}

userinfo.go

1
2
3
4
5
6
7
8
9
10
11
package routers

import "github.com/gin-gonic/gin"

func Users(r *gin.Engine) {
r.GET("/user", UsersHandler)
}

func UsersHandler(c *gin.Context) {
c.String(200, "用户模块")
}

image-20240525113449975


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!