Gin笔记

5/15/2023 Golang

# 1. 启动服务

app := gin.Default()
// ...
app.Run("127.0.0.1:88")

# 2. RESTfull

# 2.1 GET

常用get请求方式有两种,分别是QueryParams

对于Query,请求的形式为url? key1=val1&key2=val2&...& keyN=valN,参数存放在Query Params中,获取的方式为c.Query(key)c.DefaultQuery(key, val)

app.GET("/getStudent", func(c *gin.Context) {
  name := C.DefaultQuery("name", "匿名") // 指定默认值
  grade : = C.Query("grade")
})

对于Params,请求形式为url/val1/val2/.../valN,参数存放在请求uri中,获取方式为c.Param(key)

app.GET("/getStudent/:name/:grade", func(c *gin.Context) {
  name := c.Param("name")
  grade := c.Param("grade")
})

# 2.2 POST

常用的请求方式有三种,分别是Body rawBody form-dataBody x-www-form-urlencoded

Body raw可以传递JSON,是最常用的前后端传值方式,获取方式为c.ShouldBindJSON(&o)

// 将映射获取到name和grade字段,并且自动校验必填项
type Student struct {
  Name string `json:"name" binding:"required"`  
  Grade string `json:"grade" binding:"required"`  
}
app.POST("/addStudent", func(c *gin.Context) {
  var s Student
  c.ShouldBindJSON(&s)
})

Body x-www-form-urlencoded常用在登录表单中,获取方式为c.PostForm(key)c.DefaultPostForm(key, val)

type User struct {
  Name string `json:"name" binding:"required"`  
  Psw string `json:"psw" binding:"required"`  
}
app.POST("/user/login", func(c *gin.Context) {
  name := c.DefaultPostForm("name", "admin")  
  psw := c.PostForm("psw")
})

Body form-data用于文件上传,获取方式为c.FormFile(key)c.MultipartForm().File(key)

// 单文件上传
app.POST("/upload", func(c *gin.Context) {
  file, _ := c.FormFile("file")
  c.SaveUploadedFile(file, "./uploadFiles/" + file.Filename)  
})
// 多文件上传
app.POST("/uploadMulti", func(c *gin.Context) {  
  multiForm, _ := c.MultipartForm()  
  files := multiForm.File["file"]
  
  for _, file := range files {  
    c.SaveUploadedFile(file, "./uploadFiles/"+file.Filename)  
  }  
})

# 2.3 Response

c.JSON(code, gin.H{ ... }]),返回JSON

app.GET('/getSomeInfo', func(c *gin.Context){
  c.JSON(200, gin.H{
    "code": 200,
    "message": "请求成功"
    "data": {
      "id": 107,
      "name": "NOxONE"
    }
  })
}) 

c.Redirect(301, url),重定向

app.POST('/login', func(c *gin.Context){
  c.Redirect(301, "/index")
}

# 3. Router Group

定义分组路由:app.Group(url)

var task = app.Group('/task')

定义子路由

task.POST('/add', func(c *gin.Context) { ... }) // /task/add
task.POST('/delete', func(c *gin.Context) { ... }) // /task/delete
task.POST('/update', func(c *gin.Context) { ... }) // /task/update
task.GET('/info', func(c *gin.Context) { ... }) // /task/info

对于所有的子路由会共用父路由的中间件,作一些鉴权、获取token操作等

task.Use(middle1(), middle2()) // 在调task的增删改查接口时会先走middle1和middle2中间件

# 4. Middleware

中间件类型为gin.HandlerFunc,可以通过回传参数访问到c *gin.Contextgin上下文对象,从而可以在请求前和请求结束后做一些操作,同时通过c.Next()将钩子传递下去

var Logger gin.HandlerFunc = func(c *gin.Context) {
  // 请求前
  t := time.Now()
  c.Set("num", 107)

  c.Next()

  // 请求后
  status := c.Writer.Status()
  sumTime := time.Since(t)
  fmt.Println("响应时间:" + t)
  fmt.Println("响应状态:" + status)
}
var Logger2 gin.HandlerFunc = func(c *gin.Context) {
  // 请求前
  c.Set("num2", 108)

  c.Next()

  // 请求后
  fmt.Println("响应结束")
}

app := gin.New()
app.Use(Logger, Logger2)

app.GET("/test", func(c *gin.Context) {
  num := c.MustGet("num").(int)
  num2 := c.MustGet("num2).(int)
  fmt.Println(num, num2)
})

app.Run("127.0.0.1:88")
// 107 108
// 响应时间:15
// 响应状态:200
// 响应结束

对于组路由来说,若父路由使用中间件,则子路由都会共享到这个中间件

# 5. Validator

form指定映射字段,binding指定验证方法

// 预约时间表
type Booking struct {
  StartTime time.Time `form:"startTime" binding:"required,timeValid" time_format:"1970-01-01"`
  EndTime time.Time `form:"endTime" binding:"required,gtfield=StartTime,timeValid" time_format:"1970-01-01"`
}

创建校验引擎,注册校验方法

其中校验方法是validator.Func类型,通过回传参数fl validator.FieldLevel可以访问到请求参数字段,方法最终返回一个布尔值来说明是否校验通过

v, _ := binding.Validator.Engine().(*validator.Validate) // 创建校验引擎

// 定义校验方法并注册到校验引擎中
var timeValid validator.Func = func(fl validator.FieldLevel) bool { 
  val, _ := fl.Field().Inferface().(time.Time) 
  return !time.Now().After(date) // 只能在今天之后的日期 
}
v.RegisterValidation("timeValid", timeValid)

完整代码

import (
  "time"
  "github.com/gin-gonic/gin/binding"
  "github.com/go-playground/validator/v10"
)

// 预约时间表
type Booking struct {
  StartTime time.Time `form:"startTime" binding:"required,timeValid" time_format:"1970-01-01"`
  EndTime time.Time `form:"endTime" binding:"required,gtfield=StartTime,timeValid" time_format:"1970-01-01"`
}

// 定义校验方法
var timeValid validator.Func = func(fl validator.FieldLevel) bool {
  val, _ := fl.Field().Inferface().(time.Time)
  return !time.Now().After(date) // 只能在今天之后的日期
}

func main() {
  app := gin.Default()
  v, _ := binding.Validator.Engine().(*validator.Validate) // 创建校验引擎
  v.RegisterValidation("timeValid", timeValid) // 注册校验方法

  app.GET("/booking", func(c *gin.Context) {
    var b Booking
    err := c.ShouldBindWith(&b, binding.Query)
    if err != nil {
      c.JSON(99, gin.H{"error": err.Error()})
      return
    }
    c.JSON(200, gin.H{"msg": "预定成功"})
  })
}
    要么重构,
    要么享受!
    红莲华
    x
    loading...