Gin笔记
# 1. 启动服务
app := gin.Default()
// ...
app.Run("127.0.0.1:88")
# 2. RESTfull
# 2.1 GET
常用get请求方式有两种,分别是Query和Params
对于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 raw、Body form-data和Body 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": "预定成功"})
  })
}
