gin 请求参数绑定与多数据格式处理

1,016 阅读2分钟

表单实体绑定

gin提供了数据结构体和表单提交数据绑定功能,提高表单数据获取的效率。

type UserRegister struct{
    Username string `form:"username" json:"username" binding:"required"`
    Password string `form:"password" json:"password" binding:"required"`
    Phone    string `form:"phone"    json:"phone"    binding:"required"`
}

创建结构体用来接收数据,通过 tag标签 设置每个字段对应的form表单,或者json中的属性名,binding属于设置属性是否是必须。

GET

package main

import (
    "fmt"
    "log"
    "github.com/gin-gonic/gin"
)
type Student struct{
    Name string `form:"name"` 
    Classes string `form:"classes"` 
}
func main(){
    engine:=gin.Default()
    engine.GET("/hello",func(c *gin.Context) {
        fmt.Println(c.FullPath())

        var student Student
              //在查询字符串里搜索
        err := c.ShouldBindQuery(&student)
        if err!=nil{
            log.Fatal(err.Error())
        }
        fmt.Println(student)
        c.Writer.WriteString(student.Name+"登录了")
    })

    engine.Run()
}

POST

package main

import (
	"fmt"
	"log"
	"github.com/gin-gonic/gin"
)
type UserRegister struct{
    Username string `form:"username" json:"username" binding:"required"`
    Password string `form:"password" json:"password" binding:"required"`
    Phone    string `form:"phone"    json:"phone"    binding:"required"`
}
func main(){
    engine:=gin.Default()
    engine.POST("/hello",func(c *gin.Context) {
        fmt.Println(c.FullPath())

        var user UserRegister
                //可接受多种形式的参数,比如查询字符串、表单提交、JSON等
        err := c.ShouldBind(&user)
        if err!=nil{
            log.Fatal(err.Error())
        }
        fmt.Println(user)
        c.Writer.WriteString(user.Username+"注册了")
    })
    engine.Run()
}

返回数据格式

JSON

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)
func main(){
	engine:=gin.Default()
	engine.GET("/hellojson",func(c *gin.Context) {
            fullPath:="请求路径"+c.FullPath()
            fmt.Println(fullPath)
                      //缩写为 gin.H{}
            c.JSON(200,map[string]interface{}{
                "code":1,
                "message":"OK",
                "data":fullPath,
            })
	})
	
	engine.GET("/jsonstruct",func(c *gin.Context) {
            fullPath := "请求路径"+c.FullPath()
            fmt.Println(fullPath)

            resp:=Response{
                Code:1,
                Message: "OK",
                Data: fullPath,
            }
            //func (*gin.Context).JSON(code int, obj interface{})
            //因为 JSON 第二个参数是一个接口,所以要取地址&
            c.JSON(200,&resp)
    })
	engine.Run()
}
type Response struct{
	Code int
	Message string
	Data interface{}
}

Html

项目目录 image.png

main.go

package main

import (
	"fmt"
	"net/http"

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

func main(){
    r:=gin.Default()
    //配置加载静态 Html 的目录
    r.LoadHTMLGlob("./html/*")
    //配置静态资源的目录
      //html端的映射路径 //实际路径
    r.Static("/img",  "./img")
    r.GET("/html",func(c *gin.Context) {
        fullPath:="请求路径"+c.FullPath()
        fmt.Println(fullPath)

        //返回Html      
        //	对于设置的静态文件目录的路径   返回的对象接口
        c.HTML(http.StatusOK,"index.html",gin.H{
            "fullPath":fullPath,
            "title":"Gin 教程",
        })
    })
    r.Run()
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{.title}}</title>
</head>
<body>
    Gin 教程
    <br/>
当前访问路由为:{{.fullPath}}

<img src="/img/logo.jpg" alt="">
</body>
</html>

如果出现了panic: html/template: pattern matches no files: ./html/*的问题,注意当前项目打开的路径,如果go文件不在根目录,跳转到go文件所在的目录在执行 go run main.go

文件上传

单个文件上传

    r.POST("/upload",func(c *gin.Context) {
        //限制文件大小
        r.MaxMultipartMemory=8<<20 //8MB
        //表单取文件
        file,_:=c.FormFile("file")
        log.Println(file.Filename)

        //传到项目根目录,名字就用本身的
        c.SaveUploadedFile(file,file.Filename)
        c.String(200,fmt.Sprintf("%s upload!",file.Filename))
    })

多个文件上传

    r.POST("/upload",func(c *gin.Context) {
        //限制文件大小
        r.MaxMultipartMemory=8<<20 //8MB
        form,err:=c.MultipartForm()
        if err!=nil{
                c.String(http.StatusBadRequest,fmt.Sprintf("get err %s",err.Error()))
        }
        files:=form.File["files"]
        for _,file:=range files{
            //逐个存储
            if err:=c.SaveUploadedFile(file,file.Filename);err!=nil{
                c.String(http.StatusBadRequest,fmt.Sprintf("upload err %s",err.Error()))
            }
            c.String(200,fmt.Sprintf("%s upload!\n",file.Filename))
        }
    })

重定向

    r.GET("/redirect",func(c *gin.Context) {
            //支持内部和外部重定向
            c.Redirect(http.StatusMovedPermanently,"https://www.baidu.com")
    })

同步异步

  • goroutine 机制可以方便的实现异步处理
  • 在启动新的 goroutine时,不应该使用原始上下文,必须使用它的只读副本
    //异步
    r.GET("/long_async",func(c *gin.Context) {
        //需要一个副本
        copyContext:=c.Copy()
        //异步处理
        go func ()  {
            time.Sleep(3*time.Second)
            log.Println("异步执行:"+copyContext.Request.URL.Path)
        }()
    })
    //同步
    r.GET("/long_sync",func(c *gin.Context) {
        time.Sleep(3*time.Second)
        log.Println("同步执行:"+c.Request.URL.Path)
    })

image.png