Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httprouter,速度提高了近 40 倍。如果你需要极好的性能,使用 Gin 吧。
gin的github地址:https://github.com/gin-gonic/gin
在项目中使用gin框架只需要下面三步:
第一步:运行下面指令安装gin(注意go的版本要在1.15以上)
go get -u github.com/gin-gonic/gin
第二步:在项目中导入包
import "github.com/gin-gonic/gin"
第三步:一般情况下,还需要导入net/http
import "net/http"
我们编写一个例子,代码内容如下:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
//创建一个默认的引擎实例
engine := gin.Default()
//定义一个请求url为ask的GET请求
engine.GET("/ask", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"message": "hello world!",
})
})
//在8080端口启动服务
engine.Run(":8080")
}
启动上面代码,打开浏览器在上面输入http://127.0.0.1:8080/ask
,看到响应结果,至此一个简单的gin服务器搭建完成。
在gin中可以使用GET, POST, PUT, PATCH, DELETE 和OPTIONS的方法,使用方式如下:
func main() {
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
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)
// By default it serves on :8080 unless a
// PORT environment variable was defined.
router.Run()
// router.Run(":3000") for a hard coded port
}
下面通过三个例子来演示一下GET请求的参数获取。
绑定一个router的url,并建立一个处理函数handleGetParam
:
engine := gin.Default()
//http://127.0.0.1:8080/v1/wangwu/17
engine.GET("/v1/:name/:age", handleGetParam)
/**
* 通过context.Param直接拿到请求中的参数
*/
func handleGetParam(context *gin.Context) {
age := context.Param("age")
name := context.Param("name") //context.DefaultQuery("name","0") 没有值就默认
context.JSON(http.StatusOK, gin.H{
"age": age,
"name": name,
})
}
启动项目,在浏览器中输入http://127.0.0.1:8080/v1/wangwu/17
,浏览器响应结果如下,满足预期,代表参数的传值正常取到。
绑定一个router的url,并建立一个处理函数handleV2GetParam
,在这个例子中还需要创建一个Student的结构体。
//http://127.0.0.1:8080/v2/wangwu/17
engine.GET("/v2/:name/:age", handleV2GetParam)
type Student struct {
Age int `uri:"age" binding:"required"`
Name string `uri:"name" binding:"required"`
}
/**
* 通过绑定的方式获取参数
*/
func handleV2GetParam(context *gin.Context) {
var student Student
if err := context.ShouldBindUri(&student); err != nil {
context.Status(404)
return
}
context.JSON(http.StatusOK, gin.H{
"name": student.Name,
"age": student.Age,
})
}
启动项目,在浏览器中输入http://127.0.0.1:8080/v2/wangwu/17
,浏览器响应结果如下,满足预期,代表参数的传值正常取到。
绑定一个router的url,并建立一个处理函数handleV3GetParam
,这个例子是通过?
在请求url后面拼接参数。
//http://127.0.0.1:8080/v3?name=wangwu&age=18
engine.GET("/v3", handleV3GetParam)
/**
* 获取?形式传参的数据
*/
func handleV3GetParam(context *gin.Context) {
age := context.Query("age")
name := context.Query("name")
context.JSON(http.StatusOK, gin.H{
"age": age,
"name": name,
})
}
启动项目,在浏览器上输入http://127.0.0.1:8080/v3?name=wangwu&age=18
也可以拿到预期的结果。
绑定一个router的url,并建立一个处理函数handleForm
,对应代码如下:
//处理post请求from表单传参的方式
engine.POST("/v1", handleForm)
/**
* post以form表单的形式发送请求
*/
func handleForm(context *gin.Context) {
name := context.PostForm("name")
age := context.DefaultPostForm("age", string(18))
context.JSON(http.StatusOK, gin.H{
"age": age,
"name": name,
})
}
由于发送的是POST请求,我们可以在postman中进行测试,测试结果满足预期:
绑定一个router的url,并建立一个处理函数handleJson
,例子中使用到的Student结构体在上面例子有定义,其他对应代码如下:
//处理post请求json传参
engine.POST("/v2", handleJson)
/**
* post以json的形式发送请求
*/
func handleJson(context *gin.Context) {
var student Student
if err := context.ShouldBind(&student); err != nil {
fmt.Println(err.Error())
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"name": student.Name,
"age": student.Age,
})
}
启动服务,进行测试,测试结果满足预期:
编写一个url,绑定的处理器handleFile
,对应代码如下:
//处理文件上传(单文件上传)
engine.POST("/v3", handleFile)
/**
* 单文件上传
*/
func handleFile(context *gin.Context) {
file, err := context.FormFile("file")
if err != nil {
fmt.Println("产生错误:", err)
}
source := "D:\\code\\other\\go-project\\src\\project-study\\gin-study-01\\ch02\\" + file.Filename
if err := context.SaveUploadedFile(file, source); err != nil {
fmt.Println("保存文件出错:", err)
}
}
测试代码,接口调用成功之后会在指定目录下找到上传文件:
编写一个url,绑定的处理器handleFiles
,对应代码如下:
//多文件上传
engine.POST("/v4", handleFiles)
/**
* 多文件上传
*/
func handleFiles(context *gin.Context) {
form, err := context.MultipartForm()
if err != nil {
fmt.Println("处理文件出错:", err)
return
}
files := form.File
for _, v := range files {
for _, f := range v {
s := f.Filename
source := "D:\\code\\other\\go-project\\src\\project-study\\gin-study-01\\ch02\\" + s
if err := context.SaveUploadedFile(f, source); err != nil {
fmt.Println("保存文件出错:", err)
}
}
}
values := form.Value
for k, v := range values {
fmt.Printf("key:%s,value:%v", k, v)
}
}
测试接口,本测试上传两个文件都成功了:
在实际项目开发中,针对相同资源的操作请求的url的前缀一般都是一样的,在gin框架里面,我们可以通过Group实现,编写代码:
// 接口分组,这样可以保证请求接口url前缀一样
group := engine.Group("/openapi")
{
group.GET("/get", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"msg": "getsuccess",
})
})
group.POST("/post", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"msg": "postsuccess",
})
})
}
在上述例子中创建了一个Group,这个Group里面定义了两个接口,它们的请求前缀都需要带上openapi。