前言

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

官方文档地址

安装

要安装Gin软件包,需要安装Go并首先设置Go工作区。

1.首先需要安装Go(需要1.10+版本),然后可以使用下面的Go命令安装Gin。

  • go get -u github.com/gin-gonic/gin

2.将其导入代码中:

  • import “github.com/gin-gonic/gin”

3.(可选)导入net/http。例如,如果使用常量,则需要这样做http.StatusOK。

  • import “net/http”

需要注意的是,直接下载gin有可能会报错,因为毕竟这不是国内的地址,可以通过以下命令来更改源:go env -w GOPROXY=https://goproxy.cn,direct

下载完毕后,去go工程目录下的/pkg/mod/github.com/gin-gonic/查看是否有gin,如果名字带着版本什么的,改成gin就好了,否则你在引入的时候还有可能会找不到这个包。

测试一下

新建一个文件main.go

package main


import (
	"net/http"

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

func main() {
	// 1.创建路由
	r := gin.Default()
	// 2.绑定路由规则,执行的函数
	// gin.Context,封装了request和response
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "hello Salmon!")
	})
	// 3.监听端口,默认在8080
	// Run("里面不指定端口号默认为8080")
	r.Run(":8020")
}

直接运行或者编译

[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8020

ok,启动完毕,然后我们来访问一下http://127.0.0.1:8020/,显示hello Salmon!,大功告成。

path参数

path参数可以根据:xxx来定义,通过Param取值,或者通过Params.Get的方式来取值。

package main

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

func main() {
	r := gin.Default()
	r.GET("/user/:name/:com", func(c *gin.Context) {
		ok,err := c.Params.Get("name")
    // fmt.Println(c.Param("name"))
		fmt.Println(ok, err)
		c.JSON(http.StatusOK,gin.H{"message":"你好,tt "})

	})
	r.Run("0.0.0.0:8020")
}

查询参数

查询参数,又叫query参数,一般是拼接在url后面的参数,通过?开始,不同的查询参数之间,用&来拼接,例如:xxx.com/?id=1111&name=salmon,

func main() {
	r := gin.Default()
	r.GET("/user", func(c *gin.Context) {
		req := c.DefaultQuery("name","天听")
		fmt.Println(req)
		c.JSON(http.StatusOK,gin.H{"msg":req})
	})
	r.Run("0.0.0.0:8020")
}

可以通过DefaultQuery或者Query来取值,Query自不必说,DefaultQuery是有带一个默认值的。参数不存在,返回默认值,Query()若不存在,返回空串。

表单参数

  • 表单传输为post请求,http常见的传输格式为四种:
    • application/json
    • application/x-www-form-urlencoded
    • application/xml
    • multipart/form-data
  • 表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数

我们先定义一个表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Salmon</title>
</head>
<body>
<form action="http://localhost:8020/form" method="post" action="application/x-www-form-urlencoded">
    用户名:<input type="text" name="username" placeholder="请输入你的用户名">  <br>
    密&nbsp;&nbsp;&nbsp;码:<input type="password" name="userpassword" placeholder="请输入你的密码">  <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

然后使用PostForm或者DefaultPostForm来取值。

上传单个文件

  • multipart/form-data格式用于文件上传
  • gin文件上传与原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中

还是先定义一个html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
</body>
</html>

后台:

package main

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

func main() {
	r := gin.Default()
	//限制上传最大尺寸
	r.MaxMultipartMemory = 8 << 20
	r.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("file")
		if err != nil {
			c.String(500, "上传图片出错")
		}
		// c.JSON(200, gin.H{"message": file.Header.Context})
		c.SaveUploadedFile(file, file.Filename)
		c.String(http.StatusOK, file.Filename)
	})
	r.Run(":8020")
}

也可以加一些限制:

func main() {
    r := gin.Default()
    r.POST("/upload", func(c *gin.Context) {
        _, headers, err := c.Request.FormFile("file")
        if err != nil {
            log.Printf("Error when try to get file: %v", err)
        }
        //headers.Size 获取文件大小
        if headers.Size > 1024*1024*2 {
            fmt.Println("文件太大了")
            return
        }
        //headers.Header.Get("Content-Type")获取上传文件的类型
        if headers.Header.Get("Content-Type") != "image/png" {
            fmt.Println("只允许上传png图片")
            return
        }
        c.SaveUploadedFile(headers, "./video/"+headers.Filename)
        c.String(http.StatusOK, headers.Filename)
    })
    r.Run(":8020")
}

上传多个文件

照旧,html先搞上

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8020/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="files" multiple>
          <input type="submit" value="提交">
    </form>
</body>
</html>

后台:

package main

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

func main() {
	// 1.创建路由
	// 默认使用了2个中间件Logger(), Recovery()
	r := gin.Default()
	// 限制表单上传大小 8MB,默认为32MB
	r.MaxMultipartMemory = 8 << 20
	r.POST("/upload", func(c *gin.Context) {
		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()))
				return
			}
		}
		c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
	})
	//默认端口号是8080
	r.Run(":8020")
}

routes group

  • routes group是为了管理一些相同的URL,例如迭代版本不同

举个例子:

r := gin.Default()

	v1 := r.Group("/v1")
	v1.GET("/login/",func(c *gin.Context) {
		c.String(200,"v1版本")
	})

	v2 := r.Group("/v2")
	v2.GET("/login/", func(c *gin.Context) {
		c.String(200, "v2版本")
	})

url分别可以访问:/v1/login/或者v2/login/

gin的异步操作

goroutine机制可以方便地实现异步处理

另外,在启动新的goroutine时,不应该使用原始上下文,必须使用它的只读副本

r.GET("/long_async", func(c *gin.Context) {
		// 需要搞一个副本
		copyContext := c.Copy()
		//fmt.Println(copyContext.Request.URL)
		// 异步处理
		go func() {
			time.Sleep(3 * time.Second)
			log.Println("异步执行:" + copyContext.Request.URL.Path)
		}()
	})
	// 2.同步
	r.GET("/long_sync", func(c *gin.Context) {
		time.Sleep(3 * time.Second)
		log.Println("同步执行:" + c.Request.URL.Path)
	})