配置

配置代理和安装gin包

  1. go env -w GO111MODULE=on
  2. go env -w GOPROXY=https://goproxy.io,direct
  3. 安装 gin 包 go get -u github.com/gin-gonic/gin

将 gin 引入到代码中:

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

第一个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 (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
// 创建一个默认的路由引擎
r := gin.Default()

// GET请求方式;/hello:请求路径
// 客户端请求/hello路径是,会执行后面的的匿名函数
r.GET("/hello", func(c *gin.Context) {
// c.JSON:返回JSON格式的数据
// gin.H是一个map(type H map[string]any)
c.JSON(http.StatusOK, gin.H{
"message": "hello world!",
})
})

// 启动http服务,默认是8080端口
r.Run()
}

html渲染

  1. 引入静态文件

    1
    r.Static("/static", "./statics")
    1
    <link rel="stylesheet" href="/static/index.css">
    1
    <script src="/static/index.js"></script>
  2. 解析模板文件(在此之前可以自定义模板函数)

    Gin框架中使用LoadHTMLGlob()或者LoadHTMLFiles()方法进行HTML模板渲染。

    1
    2
    3
    //解析模板文件
    r.LoadHTMLFiles("templates/index.tmpl")
    r.LoadHTMLGlob("templates/**/*")
  3. 模板渲染

    1
    2
    3
    4
    // 模板渲染
    c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
    "title": "贾某某",
    })

一个栗子:

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
43
44
45
46
47
package main

import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)

func main() {
// 创建一个默认的路由引擎
r := gin.Default()
// 调用r.Static()方法去引入静态文件
r.Static("/static", "./statics")
// 自定义模板函数
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})

//解析模板文件
//r.LoadHTMLFiles("templates/index.tmpl")
r.LoadHTMLGlob("templates/**/*")

// GET请求方式;/hello:请求路径
// 客户端请求/hello路径是,会执行后面的的匿名函数
r.GET("/posts/index", func(c *gin.Context) {
// HTTP请求
// gin.H试一个map(type H map[string]any)
// 模板渲染
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "贾某某",
})
})
r.GET("/users/index", func(c *gin.Context) {
// HTTP请求
// gin.H试一个map(type H map[string]any)
// 模板渲染
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "<a href='https://jpcly.top'>贾小白</a>",
})
})

// 启动http服务
r.Run(":9090")
}

gin框架返回JSON

gin.H{}其实就是map,我们可以将数据封装成map然后再序列化发送给前端。

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

import (
"github.com/gin-gonic/gin"
"net/http"
)

func main() {
// 创建默认路由引擎
r := gin.Default()

r.GET("/aJSON", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "hello world!",
})
})

type User struct {
Name string `json:"name"`
Gender string `json:"gender"`
Age int `json:"age"`
}

r.GET("/bJSON", func(c *gin.Context) {
data := User{
Name: "梅西",
Gender: "男",
Age: 36,
}
c.JSON(http.StatusOK, data)
})

r.Run()
}

获取参数

get获取url参数

1
2
3
4
5
6
7
8
9
r.GET("/index", func(c *gin.Context) {
username := c.DefaultQuery("username", "jpc")
address := c.Query("address")
c.JSON(http.StatusOK, gin.H{
"message": "ok",
"username": username,
"address": address,
})
})

运行结果

image-20221129110858905

获取表单参数

main.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
r.GET("/index2", func(c *gin.Context) {
c.HTML(http.StatusOK, "index2.html", nil)
})
// 2.post方法获取form参数
r.POST("/index2", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
c.JSON(http.StatusOK, gin.H{
"msg": "ok",
"username": username,
"password": password,
})
})

index2.html文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index2" method="post">
<label for="username">username:</label>
<input type="text" name="username" id="username">
<br>
<label for="password">password:</label>
<input type="password" name="password" id="password">
<br>
<input type="submit" value="登录">
</form>
</body>
</html>

运行结果

image-20221129110741618

获取url路径参数

main.go文件

1
2
3
4
5
6
7
8
9
10
r.GET("/user/:username/:address", func(c *gin.Context) {
username := c.Param("username")
address := c.Param("address")
//输出json结果给调用方
c.JSON(http.StatusOK, gin.H{
"message": "ok",
"username": username,
"address": address,
})
})

参数绑定

ShouldBind()能够基于请求自动提取JSONform表单QueryString类型的数据,并把值绑定到指定的结构体对象。

下面的例子是提取quertstring数据绑定到制定的结构体对象。

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

import (
"github.com/gin-gonic/gin"
"net/http"
)

// Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}

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

// 绑定QueryString
router.GET("/loginForm", func(c *gin.Context) {
var login Login
// ShouldBind()会根据请求的Content-Type自行选择绑定器
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})

router.Run(":9090")
}

运行结果

image-20221129111851787

请求重定向

HTTP 重定向很容易。 内部、外部重定向均支持。

1
2
3
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})

路由重定向,使用 HandleContext

1
2
3
4
5
6
7
r.GET("/test", func(c *gin.Context) {
c.Request.URL.Path = "/test2"
r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
c.JSON(200, gin.H{"hello": "world"})
})

路由和路由组

路由参数

404界面

1
2
3
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusNotFound, "views/404.html", nil)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func main() {
router := gin.Default()

// 此 handler 将匹配 /user/john 但不会匹配 /user/ 或者 /user
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name)
})

// 此 handler 将匹配 /user/john/ 和 /user/john/send
// 如果没有其他路由匹配 /user/john,它将重定向到 /user/john/
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})

router.Run(":8080")
}

路由组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {
router := gin.Default()

// 简单的路由组: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}

// 简单的路由组: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}

router.Run(":8080")
}