Go语言gin框架基础
1.简介
- 基于
httprouter开发的web框架,http://github.com/julienschmidt/httprouter - 提供
Martini风格的API,但比Martini要快40倍 - 非产妇轻量级,使用起来非常简洁
2.安装与使用
1.安装
go get -u github.com/gin-gonic/gin
2.使用
package main
import "github.com/gin-gonic/gin"
func main() {
// 初始化一个默认的路由引擎
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
// 输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
})
})
// 监听8080端口
// 可以自己设置:0.0.0.0:9000
r.Run("0.0.0.0:9000")
}
- 修改全局默认404异常返回数据
r := gin.Default() // Grouping routes
r.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{
"status": 404,
"error": "404, page not exists!",
})
})
3.查询参数的获取
c.Query
http://localhost:9000/user/search?id=1
id := c.Query("id") // 1
http://localhost:9000/user/search?ids=1,2,3
ids := c.Query("ids") // 1,2,3
for _, v := range strings.Split(ids[0], ","){
fmt.Println(v)
}
c.GetQuery("id")
id, exist := c.GetQuery("id") // GetQuery可以查询该参数是否传递
if !exist {
name = "the key is not exist!"
}
c.Data(http.StatusOK, "text/plain", []byte(fmt.Sprintf("get success! %s %s", name, pwd)))
return
c.QueryArray
http://localhost:9000/user/search?id=1&id=2&id=3
id := c.QueryArray("id") // [1 2 3]
for _, v := range id {
fmt.Println(v)
}
c.QueryMap
http://localhost:9000/user/search?user[name]=小李&user[age]=21
userInfo := c.QueryMap("user")
fmt.Println(userInfo["name"]) // "小李"
fmt.Println(userInfo["age"]) // 21
c.DefaultQuery
http://localhost:9000/user/search
pwd := c.DefaultQuery("password", "123")
fmt.Println(pwd) // 123
4.路径参数的获取
c.Param
http://localhost:9000/user/1
id := c.Param("id") // 1
c.Params
http://localhost:9000/user/1,2,3
ids := c.Params
fmt.Println(ids) // [{ids 1,2,3}]
values := ids.ByName("ids")
fmt.Println(values) // 1,2,3
fmt.Println(reflect.TypeOf(values)) // string
for _, v := range strings.Split(values, ","){
fmt.Println(v)
}
5.路由冲突
解决方法参考:https://hanggi.me/post/golang/wildcard-conflict/
6.Form表单数据的获取
c.PostForm
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func userCreate(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
data := map[string]string{
"username": username,
"password": password,
}
c.JSON(http.StatusOK, gin.H{
"message": "OK",
"data": data,
})
}
func main() {
// 初始化一个默认的路由引擎
r := gin.Default()
r.POST("/user/create", userCreate)
// 监听8080端口
// 可以自己设置:0.0.0.0:9000
r.Run("0.0.0.0:9000")
}

c.PostFormMap
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func userCreate(c *gin.Context) {
user := c.PostFormMap("user")
fmt.Println(user["username"])
fmt.Println(user["password"])
c.JSON(http.StatusOK, gin.H{
"message": "OK",
"data": user,
})
}
func main() {
// 初始化一个默认的路由引擎
r := gin.Default()
r.POST("/user/create", userCreate)
// 监听8080端口
// 可以自己设置:0.0.0.0:9000
r.Run("0.0.0.0:9000")
}

7.单文件上传
c.FormFile
func uploadFile(c *gin.Context) {
// 获取文件对象
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
}
log.Println(file.Filename)
// 指定文件存储路径
dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
// 保存文件到指定的路径
c.SaveUploadedFile(file, dst)
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
})
}

c.File
c.FileAttachment
c.FileFromFS
8.多文件上传
c.MultipartForm()form.File["file"]
func manyUpload(c *gin.Context) {
form, _ := c.MultipartForm()
files := form.File["file"]
for index, file := range files {
log.Println(file.Filename)
dst := fmt.Sprintf("C:/tmp/%s+%d", file.Filename, index)
c.SaveUploadedFile(file, dst)
}
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("'%d' files uploaded!", len(files)),
})
}
- 设置文件处理内存大小(单位byte):默认为32M
router.MaxMultipartMemory = 8 << 20- 8 << 20 相当于 8 * 2**20

9.文件下载
c.File
func downloadFile(c *gin.Context) {
c.Header("Content-Type", "application/octet-stream")
// 关键点
c.Header("Content-Disposition", "attachment; filename=111.png")
c.Header("Content-Transfer-Encoding", "binary")
c.File("C:/tmp/111.png")
}
c.FileAttachment
func downloadFile(c *gin.Context) {
c.FileAttachment("C:/tmp/111.png", "bbb.jpg")
}
10.路由分组
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func login(c *gin.Context) {
fmt.Println("visit", c.Query("version"), "version api")
c.JSON(200, gin.H{
"message": "OK",
"version": c.Query("version"),
})
}
func main() {
router := gin.Default()
v1 := router.Group("/v1")
v1.GET("/login", login)
v2 := router.Group("/v2")
v2.GET("/login", login)
router.Run()
}
11.参数绑定
1.为什么要参数绑定,本质上是方便,提高开发效率
- 通过反射机制,自动提取
querystring、form表单、json、xml等,到struct中 - 通过
http协议中的context type,识别是json、xml或者表单 - 大部分参数的绑定都可以使用
c.ShouldBind直接解决
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Login struct {
// 如果通过json格式提交数据,则使用username和password
// 如果通过form表单提交数据,则使用user和pwd
User string `form:"user" json:"username" binding:"required"`
Password string `form:"pwd" json:"password" binding:"required"`
}
2.c.ShouldBindJSON:绑定json请求体
func login1(c *gin.Context) {
var login Login
if err := c.ShouldBindJSON(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": login.User,
"pwd": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
}

3.c.ShouldBind:绑定Form表单请求体
func login2(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": login.User,
"pwd": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
}

4.c.ShouldBindQuery:绑定查询参数
func login3(c *gin.Context) {
var login Login
if err := c.BindQuery(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": login.User,
"pwd": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
}

type User struct {
Name string `binding:"required"` //注意此处添加了binding注解,便于测试
}
func user(c *gin.Context) {
var user User
if err := c.BindQuery(&user); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": user.Name,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
}
}

4.c.ShouldBindBodyWith
ShouldBindJSON多次绑定bug:https://blog.csdn.net/yes169yes123/article/details/106204252
12.字段验证
13.渲染
1.gin.Context.JSON
map形式
func login(c *gin.Context) {
// gin.H 是一个 map 对象
c.JSON(http.StatusOK, gin.H{
"message": "OK",
"data": "",
})
}
struct形式
func login(c *gin.Context) {
var resp struct {
Message string `json:"message"`
Data struct {
Username string `json:"username"`
Password string `json:"password"`
} `json:"data"`
}
resp.Message = "OK"
resp.Data.Username = "admin"
resp.Data.Password = "123456"
c.JSON(http.StatusOK, resp)
// c.IndentedJSON(http.StatusOK, resp)
}

2.gin.Context.XML
func login(c *gin.Context) {
type UserInfo struct {
Username string `xml:"username"`
Password string `xml:"password"`
}
type Login struct {
Message string `xml:"result"`
Data UserInfo `xml:"UserInfo"`
}
user := Login{
Message: "OK",
Data: UserInfo{
Username: "admin",
Password: "123456",
},
}
c.XML(http.StatusOK, user)
}

3.gin.Context.HTML
func index(c *gin.Context) {
c.HTML(http.StatusOK, "index/index.html", gin.H{
"title": "Posts",
})
}
func main() {
router := gin.Default()
// 加载templates下的所有模板文件
// 从src下开始查找,所以templates是相对于src的路径
// 如果templates位于项目根路径
// 项目路径:src/project
// ./project/templates/index/index.html
router.LoadHTMLGlob("./project/templates/**/*")
router.Run()
}
templates/index/index.html
{{ define "index/index.html" }}
<html>
<h1>
{{ .title }}
</h1>
</html>
{{ end }}

14.静态文件代理
func main() {
router := gin.Default()
router.Static("/static", "./static/")
router.Run()
}
http://localhost:8080/static/111.png
15.中间件
1.定义
- Gin框架允许在请求处理的过程中,加入用户自己的钩子函数,这个钩子函数就叫做中间件
- 因此,可以使用中间件处理一些公共业务逻辑,比如耗时统计,日志打印,登录校验等
2.使用
- 中间件的定义
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 可以设置一些公共参数
c.Set("example", "12345")
// 等待其他中间件先执行
c.Next()
// 获取耗时
latency := time.Since(t)
fmt.Print("Cost:", latency)
}
}
- 中间件引用
func main() {
r := gin.New()
r.Use(StatCost()) // 引用中间件
r.GET("/index", func(c *gin.Context) {
example := c.MustGet("example").(string)
fmt.Println(example)
c.JSON(http.StatusOK, gin.H{
"message": "success",
})
})
r.Run()
}
http://localhost:8080/index
[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 /index --> main.main.func1 (2 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on localhost:8080
12345
Cost:998µs

浙公网安备 33010602011771号