gin简介

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

1 GIN初始

使用gin编写一个接口并返回对象

package main
​
import "github.com/gin-gonic/gin"
​
type Resource struct {
    Code int            `json:"code"`
    Msg  string         `json:"msg"`
    Data map[string]any `json:"data"`
}
​
func Index(c *gin.Context) {
​
    c.JSON(200, Resource{
        Code: 0,
        Msg:  "成功",
        Data: map[string]any{"code": "段段"},
    })
}
func main() {
    //关闭多余的日志 debug
    gin.SetMode("release")
    //初始化
    c := gin.Default()
​
    //定义路由
    c.GET("index", Index)
​
    c.Run(":8080")
}
​

  1. c := gin.Default():这是默认的服务器。使用gin的Default方法创建一个路由Handler

  2. c.GET("index", Index) 然后通过Http方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把requestresponse都封装到了gin.Context的上下文环境中。

  3. 最后启动路由的Run方法监听端口。还可以用http.ListenAndServe(":8080", router),或者自定义Http服务器配置。

  4. c.Run("127.0.0.1:8000") 只能本机访问

2 响应体

2.1 封装返回统一响应

建立res文件夹,放入响应代码

package res
​
import "github.com/gin-gonic/gin"
​
type Response struct {
    Code int    `json:"code"`
    Msg  string `json:"msg"`
    data any
}
​
var codeMap = map[int]string{
    10001: "权限错误",
    10002: "角色错误",
}
​
func response(c *gin.Context, code int, msg string, data any) {
    c.JSON(code, Response{
        Code: code,
        Msg:  msg,
        data: data,
    })
}
​
func Ok(c *gin.Context, msg string, data any) {
​
    response(c, 200, msg, data)
}
​
func OkWithData(c *gin.Context, data any) {
    Ok(c, "成功", data)
}
​
func OkWithMsg(c *gin.Context, msg string) {
    Ok(c, msg, make(map[string]any))
​
}
​
func Fail(c *gin.Context, msg string, code int) {
    response(c, code, msg, nil)
}
​
func FailWithCode(c *gin.Context, code int) {
    msg, e := codeMap[code]
    if !e {
        msg = "服务错误"
    }
    response(c, 200, msg, nil)
}
​
func FailWithMsg(c *gin.Context, msg string) {
    response(c, 200, msg, nil)
}
​

2.2 JSON响应测试

package main
​
import (
    "github.com/gin-gonic/gin"
    "go_stuty/res"
)
​
func main() {
​
    g := gin.Default()
​
    g.GET("index", func(c *gin.Context) {
        c.JSON(200, gin.H{"msg": "成功", "data": map[string]any{"code": "段段"}, "code": 200})
    })
​
    g.POST("users", func(c *gin.Context) {
        res.Ok(c, "用户信息", gin.H{
            "username": "段段",
            "age":      30,
        })
    })
​
    g.GET("login", func(c *gin.Context) {
        res.OkWithMsg(c, "登录成功")
    })
    g.GET("fails", func(c *gin.Context) {
        res.FailWithCode(c, 10001)
    })
    g.Run(":8080")
}
​

2.3 HTML响应测试

package main
​
import "github.com/gin-gonic/gin"
​
func main() {
​
    g := gin.Default()
    //加载路径下所有文件
    g.LoadHTMLGlob("templates/*")
    //单个文件加载
    g.LoadHTMLFiles("templates/index.html")
    g.GET("index", func(c *gin.Context) {
        c.HTML(200, "index.html", map[string]string{"title": "段段主题"})
    })
​
    g.Run(":8080")
}
​

1、注意绝对和相对路径加载问题

2、//加载路径下所有文件 g.LoadHTMLGlob("templates/*")

3、//单个文件加载 g.LoadHTMLFiles("templates/index.html")

4、前后端不分离的写法 map[string]string{"title": "段段主题"}

返回修改html主题

c.HTML(200, "index.html", map[string]string{"title": "段段主题"})

html

<title>{{.title}}</title>

5、部署方式

前后端分离

前端打包引入后端单独部署

2.4 文件响应测试

package main
​
import "github.com/gin-gonic/gin"
​
func main() {
​
    g := gin.Default()
​
    g.GET("download", func(c *gin.Context) {
        c.Header("Content-Type", "application/octet-stream")
        c.Header("Content-Disposition", "attachment;filename=index.html")
        c.File("templates/index.html")
    })
​
    g.Run(":8080")
}
​

Content-Type设置传输类型

只能GET请求

2.5 静态文件响应测试

package main
​
import "github.com/gin-gonic/gin"
​
func main() {
​
    g := gin.Default()
    //通过文件夹别名st  访问static下所有的文件
    g.Static("st", "static")
    //通过别名  st  单独访问index.html
//  g.StaticFile("st", "static/index.html")
    g.Run(":8080")
}
​

g.Static("st", "static") st别名 static文件夹路径

3、请求

3.1 请求参数

package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
​
func main() {
​
    g := gin.Default()
​
    g.GET("index", func(c *gin.Context) {
        name, _ := c.GetQuery("name")
        //多个参数的情况 key=123&key=456
        key, _ := c.GetQueryArray("key")
        age, _ := c.GetQuery("age")
        fmt.Println(name, age, key)
    })
​
    g.Run(":8080")
}

请求连接 http://127.0.0.1:8080/index?name=%E6%AE%B5%E6%AE%B5&age=30&key=123&key=456

3.2 动态参数

package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
​
func main() {
    g := gin.Default()
​
    g.GET("index/:id/:name", func(c *gin.Context) {
        id := c.Param("id")
        name := c.Param("name")
        fmt.Println(name, id)
    })
    g.Run(":8080")
}
​

3.3 表单参数

package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
​
func main() {
    g := gin.Default()
    g.POST("index", func(c *gin.Context) {
        name := c.PostForm("name")
        key, _ := c.GetPostForm("key")
        fmt.Print(name, key)
    })
    g.Run(":8080")
}
​

name := c.PostForm("name") 传空值或者不传 默认打印都是空;不好区分

key, _ := c.GetPostForm("key")传空值或者不传 _ 空值是true,不传是false

3.4 文件上传

文件上传及路径存储

package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io"
    "os"
)
​
func main() {
    g := gin.Default()
    g.POST("index", func(c *gin.Context) {
        file, err := c.FormFile("file")
        if err != nil {
            fmt.Println(err)
            return
        }
        //文件名称
        filename := file.Filename
        //大小
        size := file.Size
        fmt.Println(filename, size)
        openFile, _ := file.Open()
        bataByte, _ := io.ReadAll(openFile)
        err = os.WriteFile("xxx.jpg", bataByte, 0666)
        fmt.Println(err)
    })
    g.Run(":8080")
}

简单存储写法

err = c.SaveUploadedFile(file, "aaa.png")
fmt.Println(err)

4、bind绑定器

4.1 参数绑定

4.1.1 查询参数
package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
​
func main() {
    g := gin.Default()
    g.GET("index", func(c *gin.Context) {
        type User struct {
            Name string `form:"name"`
            Age  int    `form:"age"`
        }
        var user User
        err := c.ShouldBindQuery(&user)
        fmt.Println(err, user)
    })
    g.Run(":8080")
}

访问路径 http://127.0.0.1:8080/index?name=段段&age=30

type User struct {
            Name string `form:"name"`
            Age  int    `form:"age"`
}

c.ShouldBindQuery(&user) 查询参数

form:"name" 之间不能有空格

4.1.2 路径参数
package main
​
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
​
func main() {
    g := gin.Default()
    g.GET("index/:name/:age", func(c *gin.Context) {
        type User struct {
            Name string `uri:"name"`
            Age  int    `uri:"age"`
        }
        var user User
        err := c.ShouldBindUri(&user)
        fmt.Println(err, user)
    })
    g.Run(":8080")
}

访问路径 http://127.0.0.1:8080/index/段段/30

uri:"name" 之间不能有空格

c.ShouldBindUri(&user) 路径参数

4.1.3 表单参数
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)
func main() {
	g := gin.Default()
	g.POST("index", func(c *gin.Context) {
		type User struct {
			Name string `form:"name"`
			Age  int    `form:"age"`
		}
		var user User
		err := c.ShouldBind(&user)
		fmt.Println(err, user)
	})
	g.Run(":8080")
}

c.ShouldBind(&user) 表单参数

请求

http://localhost:8080/index
form-data
4.1.4 JSON参数
package main

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

func main() {
	g := gin.Default()
	g.POST("index", func(c *gin.Context) {
		type User struct {
			Name string `json:"name"`
			Age  int    `json:"age"`
		}
		var user User
		err := c.ShouldBind(&user)
		fmt.Println(err, user)
	})
	g.Run(":8080")
}

请求

http://localhost:8080/index
{
  "name":"段段",
  "age":30
}

.....比如headers

4.2 bind规则校验

4.2.1 常用校验
// 不能为空,并且不能没有这个字段
required: 必填字段,如:binding:"required"  

// 针对字符串的长度
min 最小长度,如:binding:"min=5"
max 最大长度,如:binding:"max=10"
len 长度,如:binding:"len=6"

// 针对数字的大小
eq 等于,如:binding:"eq=3"
ne 不等于,如:binding:"ne=12"
gt 大于,如:binding:"gt=10"
gte 大于等于,如:binding:"gte=10"
lt 小于,如:binding:"lt=10"
lte 小于等于,如:binding:"lte=10"

// 针对同级字段的
eqfield 等于其他字段的值,如:PassWord string `binding:"eqfield=Password"`
nefield 不等于其他字段的值


- 忽略字段,如:binding:"-"
4.2.2 内置校验
// 枚举  只能是red 或green
oneof=red green 

// 字符串  
contains=fengfeng  // 包含fengfeng的字符串
excludes // 不包含
startswith  // 字符串前缀
endswith  // 字符串后缀

// 数组
dive  // dive后面的验证就是针对数组中的每一个元素

// 网络验证
ip
ipv4
ipv6
uri
url
// uri 在于I(Identifier)是统一资源标示符,可以唯一标识一个资源。
// url 在于Locater,是统一资源定位符,提供找到该资源的确切路径

// 日期验证  1月2号下午3点4分5秒在2006年
datetime=2006-01-02
4.2.3 校验代码样例
package main

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

func main() {
	g := gin.Default()
	g.POST("index", func(c *gin.Context) {
		type User struct {
			// binding:"required" 非空校验;,min=5 最小5位字符串 ;校验多个逗号分割
			Name string `json:"name" binding:"required,min=5"`
			Age  int    `json:"age"`
		}
		var user User
		err := c.ShouldBind(&user)
		fmt.Println(err, user)
	})
	g.Run(":8080")
}

"required" 非空校验;,min=5 最小5位字符串 ;校验多个逗号分割

Name string json:"name" binding:"required,min=5"

自定义校验中文校验返回.....

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐