Gin框架使用详解

1.什么是Gin
Gin是go编写的一个web应用框架。git

2.Gin安装github

go get github.com/gin-gonic/gin

3.Gin使用示例web

package main

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

func main() {
    // 初始化引擎
    engine := gin.Default()
    // 注册一个路由和处理函数
    engine.Any("/", WebRoot)
    // 绑定端口,而后启动应用
    engine.Run(":9205")
}

/**
* 根请求处理函数
* 全部本次请求相关的方法都在 context 中,完美
* 输出响应 hello, world
*/
func WebRoot(context *gin.Context) {
    context.String(http.StatusOK, "hello, world")
}

运行结果:
json

4.路由(Router)
1)restful api
注册路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONSapi

// 省略的代码 ...

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

    router.GET("/someGet", getting)
    router.POST("/somePost", posting)
    router.PUT("/somePut", putting)
    router.DELETE("/someDelete", deleting)
    router.PATCH("/somePatch", patching)
    router.HEAD("/someHead", head)
    router.OPTIONS("/someOptions", options)

    // 默认绑定 :8080
    router.Run()
}

2)动态路由(参数路由)
如/user/:idrestful

// 省略的代码 ...

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

    // 注册一个动态路由
    // 能够匹配 /user/joy
    // 不能匹配 /user 和 /user/
    router.GET("/user/:name", func(c *gin.Context) {
        // 使用 c.Param(key) 获取 url 参数
        name := c.Param("name")
        c.String(http.StatusOK, "Hello %s", name)
    })

    // 注册一个高级的动态路由
    // 该路由会匹配 /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")
}

// 省略的代码 ...

3)路由组
url统一前缀app

// 省略的代码 ...

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

    // 定义一个组前缀
    // /v1/login 就会匹配到这个组
    v1 := router.Group("/v1")
    {
        v1.POST("/login", loginEndpoint)
        v1.POST("/submit", submitEndpoint)
        v1.POST("/read", readEndpoint)
    }

    // 定义一个组前缀
    // 不用花括号包起来也是能够的。上面那种只是看起来会统一一点。看你我的喜爱
    v2 := router.Group("/v2")
    v2.POST("/login", loginEndpoint)
    v2.POST("/submit", submitEndpoint)
    v2.POST("/read", readEndpoint)

    router.Run(":8080")
}

// 省略的代码 ...

5.中间件(middleware)
如验证Auth,身份鉴别,集中处理返回的数据等等。
1)单个路由中间件框架

// 省略的代码 ...

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

    // 注册一个路由,使用了 middleware1,middleware2 两个中间件
    router.GET("/someGet", middleware1, middleware2, handler)
  
    // 默认绑定 :8080
    router.Run()
}

func handler(c *gin.Context) {
    log.Println("exec handler")
}

func middleware1(c *gin.Context) {
    log.Println("exec middleware1")
  
    //你能够写一些逻辑代码
  
    // 执行该中间件以后的逻辑
    c.Next()
}

// 省略的代码 ...

c.Next()控制调用逻辑curl

2)路由组使用中间件
中间件放到路由组Group中函数

// 省略的代码 ...

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

    // 定义一个组前缀, 并使用 middleware1 中间件
    // 访问 /v2/login 就会执行 middleware1 函数
    v2 := router.Group("/v2", middleware1)
    v2.POST("/login", loginEndpoint)
    v2.POST("/submit", submitEndpoint)
    v2.POST("/read", readEndpoint)

    router.Run(":8080")
}

// 省略的代码 ...

6.参数
1)Url查询参数
使用c.Query方法,该方法始终返回一个string类型的数据。

// 省略的代码 ...

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

    // 注册路由和Handler
    // url为 /welcome?firstname=Jane&lastname=Doe
    router.GET("/welcome", func(c *gin.Context) {
        // 获取参数内容
        // 获取的全部参数内容的类型都是 string
        // 若是不存在,使用第二个当作默认内容
        firstname := c.DefaultQuery("firstname", "Guest")
        // 获取参数内容,没有则返回空字符串
        lastname := c.Query("lastname") 

        c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    })
    router.Run(":8080")
}

2)表单和body参数(Multipart/Urlencoded Form)
对于POST请求,不管是multipart/form-data,仍是application/x-www-form-urlencoded格式,均可以使用c.PostForm获取到参数,该方法始终返回一个string类型的数据

// 省略的代码 ...

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

    router.POST("/form_post", func(c *gin.Context) {
        // 获取post过来的message内容
        // 获取的全部参数内容的类型都是 string
        message := c.PostForm("message")
        // 若是不存在,使用第二个当作默认内容
        nick := c.DefaultPostForm("nick", "anonymous")

        c.JSON(200, gin.H{
            "status":  "posted",
            "message": message,
            "nick":    nick,
        })
    })
    router.Run(":8080")
}

3)上传文件
使用c.FormFile获取文件

// 省略的代码 ...

func main() {
    router := gin.Default()
    // 设置文件上传大小 router.MaxMultipartMemory = 8 << 20  // 8 MiB
    // 处理单一的文件上传
    router.POST("/upload", func(c *gin.Context) {
        // 拿到这个文件
        file, _ := c.FormFile("file")
        log.Println(file.Filename)
        c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
    })
  
    // 处理多个文件的上传
    router.POST("/uploads", func(c *gin.Context) {
        form, _ := c.MultipartForm()
        // 拿到集合
        files := form.File["upload[]"]
        for _, file := range files {
            log.Println(file.Filename)
        }
        c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
    })
    router.Run(":8080")
}

使用curl工具测试一下:

# 单一文件上传
$ curl -X POST http://localhost:8080/upload \
  -F "file=@/Users/appleboy/test.zip" \
  -H "Content-Type: multipart/form-data"

# 多文件上传
$ curl -X POST http://localhost:8080/uploads \
  -F "upload[]=@/Users/appleboy/test1.zip" \
  -F "upload[]=@/Users/appleboy/test2.zip" \
  -H "Content-Type: multipart/form-data"

4)JSON参数(application/json)
使用c.GetRawData

// 省略的代码 ...

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

    router.POST("/post", func(c *gin.Context) {
        // 获取原始字节
        d, err := c.GetRawData()
        if err!=nil {
            log.Fatalln(err)
        }
        log.Println(string(d))
        c.String(200, "ok")
    })
    router.Run(":8080")
}

curl请求示例:

$ curl -v -X POST \
  http://localhost:8080/post \
  -H 'content-type: application/json' \
  -d '{ "user": "manu" }'

7.数据绑定
将用户传来的参数自动跟咱们定义的结构体绑定在一块儿
1)绑定Url查询参数
使用c.ShouldBindQuery方法

package main

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

// 定义一个 Person 结构体,用来绑定 url query
type Person struct {
    Name    string `form:"name"` // 使用成员变量标签订义对应的参数名
    Address string `form:"address"`
}

func main() {
    route := gin.Default()
    route.Any("/testing", startPage)
    route.Run(":8085")
}

func startPage(c *gin.Context) {
    var person Person
    // 将 url 查询参数和person绑定在一块儿
    if c.ShouldBindQuery(&person) == nil {
        log.Println("====== Only Bind By Query String ======")
        log.Println(person.Name)
        log.Println(person.Address)
    }
    c.String(200, "Success")
}

2)绑定url查询参数和POST参数
使用c.ShouldBind方法,该方法会检查url查询参数和POST参数,而且会根据content-type类型,优先匹配JSON或XML,以后才是Form

package main

import "log"
import "github.com/gin-gonic/gin"
import "time"

// 定义一个 Person 结构体,用来绑定数据
type Person struct {
    Name     string    `form:"name"`
    Address  string    `form:"address"`
    Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}

func main() {
    route := gin.Default()
    route.GET("/testing", startPage)
    route.Run(":8085")
}

func startPage(c *gin.Context) {
    var person Person
    // 绑定到 person
    if c.ShouldBind(&person) == nil {
        log.Println(person.Name)
        log.Println(person.Address)
        log.Println(person.Birthday)
    }

    c.String(200, "Success")
}

8.数据验证
Gin提供了数据检验的方法,Gin的数据验证是和数据绑定结合在一块儿的,只须要在数据绑定的结构体成员变量的标签添加bingding规则便可。

// 省略的代码 ...

// 定义的 Login 结构体
// 该 struct 能够绑定在 Form 和 JSON 中
// binding:"required" 意思是必要参数。若是未提供,Bind 会返回 error
type Login struct {
    User     string `form:"user" json:"user" binding:"required"`
    Password string `form:"password" json:"password" binding:"required"`
}

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

    // POST 到这个路由一段 JSON, 如 ({"user": "manu", "password": "123"})
    router.POST("/loginJSON", func(c *gin.Context) {
        var json Login
        // 验证数据并绑定
        if err := c.ShouldBindJSON(&json); err == nil {
            if json.User == "manu" && json.Password == "123" {
                c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
            } else {
                c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            }
        } else {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        }
    })

    // POST 到这个路由一个 Form 表单 (user=manu&password=123)
    router.POST("/loginForm", func(c *gin.Context) {
        var form Login
        // 验证数据并绑定
        if err := c.ShouldBind(&form); err == nil {
            if form.User == "manu" && form.Password == "123" {
                c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
            } else {
                c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            }
        } else {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        }
    })

    router.Run(":8080")
}

9.输出响应
Gin提供了多种常见格式的输出,包括HTML, String, JSON, XML, YAML
1)String

// 省略的代码 ...

func Handler(c *gin.Context) {
    // 使用 String 方法便可
    c.String(200, "Success")
}

// 省略的代码 ...

2)JSON, XML, YAML
gin.H表示实例化一个json对象

// 省略的代码 ...

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

    // gin.H 本质是 map[string]interface{}
    r.GET("/someJSON", func(c *gin.Context) {
        // 会输出头格式为 application/json; charset=UTF-8 的 json 字符串
        c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    })

    r.GET("/moreJSON", func(c *gin.Context) {
        // 直接使用结构体定义
        var msg struct {
            Name    string `json:"user"`
            Message string
            Number  int
        }
        msg.Name = "Lena"
        msg.Message = "hey"
        msg.Number = 123
        // 会输出  {"user": "Lena", "Message": "hey", "Number": 123}
        c.JSON(http.StatusOK, msg)
    })

    r.GET("/someXML", func(c *gin.Context) {
        // 会输出头格式为 text/xml; charset=UTF-8 的 xml 字符串
        c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    })

    r.GET("/someYAML", func(c *gin.Context) {
        // 会输出头格式为 text/yaml; charset=UTF-8 的 yaml 字符串
        c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
    })

    r.Run(":8080")
}

// 省略的代码 ...

3)HTML
待实现

10.其余 Gin没有提供ORM,CONFIG组件,能够由开发者本身选择。

相关文章
相关标签/搜索