1、简介

简单使用

1、安装gin库

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

2、启动简单的服务

package main

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

func main() {
	// 创建路由
    // 默认使用中间件Logger(), Recovery(),如果不需要使用中间件,可以使用gin.New()
	router := gin.Default()
	// 绑定路由规则
	router.GET("/demo", func(context *gin.Context) {
		context.String(http.StatusOK, "hello gin!")
	})
	// 监听端口,开启服务
	router.Run(":8080")
}

参数获取

GET

restful-url传参

router.GET("/demo/:name", func(context *gin.Context) {
    name := context.Param("name")
    context.String(http.StatusOK, "accept param name = %s", name)
})

?传参

router.GET("/demo", func(context *gin.Context) {
    name := context.Query("name")
    // 设置默认值
    age := context.DefaultQuery("age", "18")
    context.String(http.StatusOK, "accept param name = %s,age = %s", name, age)
})

POST

表单参数

表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencodedfrom-data格式的参数

router.POST("/form", func(context *gin.Context) {
    // 直接获取
    account := context.PostForm("account")
    // 获取,加默认值
    password := context.DefaultPostForm("password", "123456")
    fmt.Println(account)
    fmt.Println(password)
    context.String(http.StatusOK, "account:%s,password:%s", account, password)
})

数据绑定

JSON

package main

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

type Login struct {
    // 如果tag为binding:"required",那么这个参数如果不传将会报错
	Account  string `json:"account" binding:"required"`
	Password string `json:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	router.POST("/form", func(context *gin.Context) {
		var login Login
		err := context.ShouldBindJSON(&login)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Printf("%+v\n", login)

		// 返回json
		context.JSON(http.StatusOK, login)
	})
	router.Run(":8080")
}

表单参数

package main

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

type Login struct {
	Account  string `form:"account" binding:"required"`
	Password string `form:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	router.POST("/form", func(context *gin.Context) {
		var login Login
		if err := context.Bind(&login); err != nil {
			fmt.Println(err)
		}
		context.JSON(http.StatusOK, login)
	})
	router.Run(":8080")
}

restful-url

package main

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

type Login struct {
	Account  string `uri:"account" binding:"required"`
	Password string `uri:"password" binding:"required"`
}

func main() {
	router := gin.Default()
    router.GET("/form/:account/:password", func(context *gin.Context) {
		var login Login
		if err := context.ShouldBindUri(&login); err != nil {
			fmt.Println(err)
		}
		context.JSON(http.StatusOK, login)
	})
	router.Run(":8080")
}

响应

gin支持json、结构体、XML、YAML、ProtoBuf多种响应类型

package main

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

type Login struct {
	Account  string `form:"account" binding:"required"`
	Password string `form:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	// json
	router.GET("/test1", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{"account": "root", "password": "123456"})
		//gin.H实际是type H map[string]any,相当于:
		//context.JSON(http.StatusOK,map[string]string{"account":"root","password":"123456"})
	})
	// 构造体
	router.GET("/test2", func(context *gin.Context) {
		lo := Login{
			Account:  "root",
			Password: "123456",
		}
		context.JSON(http.StatusOK, lo)
	})
	// xml
	router.GET("/test3", func(context *gin.Context) {
		context.XML(http.StatusOK, gin.H{"account": "root", "password": "123456"})
	})
	// yaml
	router.GET("/test4", func(context *gin.Context) {
		context.YAML(http.StatusOK, gin.H{"account": "root", "password": "123456"})
	})
	router.Run(":8080")
}

转发和重定向

重定向

router.GET("/redirect", func(context *gin.Context) {
    context.Redirect(http.StatusMovedPermanently, "https://www.ygang.top")
})

转发

router := gin.Default()
router.GET("/forward", func(context *gin.Context) {
    context.Request.URL.Path = "/target"
    router.HandleContext(context)
})
router.GET("/target", func(context *gin.Context) {
    context.String(http.StatusOK, "success")
})

路由组

routes group是为了管理一些相同的URL,类似于java在controller类上面声明的@RequestMapping来管理的一组路由

package main

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

func main() {
	router := gin.Default()
	testRouter := router.Group("/test")
	{
		testRouter.GET("/t1", func(context *gin.Context) {
			context.String(http.StatusOK, "%s", "success1")
		})
		testRouter.GET("/t2", func(context *gin.Context) {
			context.String(http.StatusOK, "%s", "success2")
		})
	}
	router.Run(":8080")
}

分别请求地址是:/test/t1/test/t2

404页面设置

gin框架实现默认的404的页面,我们也可以自己定义

package main

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

func main() {
	router := gin.Default()
	router.NoRoute(func(context *gin.Context) {
		context.String(http.StatusOK, "%s", "404 page not found")
	})
	router.Run(":8080")
}

日志

package main

import (
    "io"
    "os"

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

func main() {
    gin.DisableConsoleColor()

    // Logging to a file.
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)

    // 如果需要同时将日志写入文件和控制台,使用以下代码。
    // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
    r := gin.Default()
    r.GET("/test", func(c *gin.Context) {
        c.String(200, "success")
    })
    r.Run()
}

上传文件

package main

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

func main() {
	router := gin.Default()
	// 限制表单上传文件大小8m,默认32m
	router.MaxMultipartMemory = 8 << 20
	router.POST("/file", func(context *gin.Context) {
		f, err := context.FormFile("file")
		if err != nil {
			fmt.Println(err)
		}
		fn := f.Filename
		fmt.Printf("文件大小%d\n", f.Size)
		fmt.Printf("文件名称%s\n", fn)
		context.SaveUploadedFile(f, "./"+fn)
	})
	router.Run(":8080")
}

多个文件

package main

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

func main() {
	router := gin.Default()
	// 限制表单上传文件大小8m,默认32m
	router.MaxMultipartMemory = 8 << 20
	router.POST("/file", func(context *gin.Context) {
		form, err := context.MultipartForm()
		if err != nil {
			fmt.Println(err)
		}
		// files是map[string][]*FileHeader
		files := form.File["files"]
		for _, fi := range files {
			fName := fi.Filename
			size := fi.Size
			fmt.Printf("文件大小%d\n", size)
			context.SaveUploadedFile(fi, "./"+fName)
		}

	})
	router.Run(":8080")
}