【GO基础学习】gin的使用

文章目录


模版使用流程

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 World!")
   })
   // 3.监听端口,默认在8080
   // Run("里面不指定端口号默认为8080") 
   r.Run(":8000")
}

运行,访问:http://localhost:8000/

后面为了减少累赘代码,只展示路由规则部分代码编写,创建路由,以及端口监听部分代码保存相同。


参数传递

  1. API传参:可以通过Context的Param方法来获取API参数。
go 复制代码
r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "Hello "+name+"!")
	})
go 复制代码
r.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		c.String(http.StatusOK, "Hello "+name+"!"+"Action "+action)
	})

*action 表示一个通配路径参数,可以匹配 URL 剩余部分的路径,并且会包含匹配部分的斜杠 /

  1. URL传参:URL参数可以通过DefaultQuery()Query()方法获取,DefaultQuery()若参数不存在,返回默认值,Query()若不存在,返回空串。

DefaultQuery默认值只支持string类型:

go 复制代码
func (c *Context) DefaultQuery(key, defaultValue string) string {
	if value, ok := c.GetQuery(key); ok {
		return value
	}
	return defaultValue
}
go 复制代码
r.GET("/user", func(c *gin.Context) {
		name := c.DefaultQuery("name", "Test")
		ageStr := c.DefaultQuery("age", "18")
		age, err := strconv.Atoi(ageStr)
		if err != nil {
			c.String(http.StatusBadRequest, "Invalid age")
			return
		}
		c.String(http.StatusOK, fmt.Sprintf("%s is %d years old", name, age))
	})
  1. 表单传值
html 复制代码
<form action="http://localhost:8000/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>
go 复制代码
r.POST("/form", func(c *gin.Context) {
        types := c.DefaultPostForm("type", "post")
        username := c.PostForm("username")
        password := c.PostForm("userpassword")
        c.String(http.StatusOK, fmt.Sprintf("username:%s,password:%s,type:%s", username, password, types))
    })
  1. 文件上传

单个文件:

html 复制代码
<form action="http://localhost:8000/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
go 复制代码
// 限制上传文件大小 (10 MiB)
    r.MaxMultipartMemory = 10 << 20 // 10 MiB

    // 文件上传路由
    r.POST("/upload", func(c *gin.Context) {
        // 获取文件
        file, err := c.FormFile("file")
        if err != nil {
            c.String(http.StatusBadRequest, "File upload error: %s", err.Error())
            return
        }

        // 检查文件类型 (仅允许 image/png)
        mimeType := file.Header.Get("Content-Type")
        if mimeType != "image/png" {
            c.String(http.StatusBadRequest, "Invalid file type: %s. Only PNG images are allowed.", mimeType)
            return
        }

        // 保存文件到目标路径
        dst := filepath.Join("./uploads", file.Filename)
        if err := c.SaveUploadedFile(file, dst); err != nil {
            c.String(http.StatusInternalServerError, "Could not save file: %s", err.Error())
            return
        }

        c.String(http.StatusOK, "File uploaded successfully: %s", file.Filename)
    })

多个文件:

go 复制代码
// 限制上传文件大小 (10 MiB)
    r.MaxMultipartMemory = 10 << 20 // 10 MiB

    // 多文件上传路由
    r.POST("/upload/multiple", func(c *gin.Context) {
        // 获取表单文件 (key 为 "files")
        form, err := c.MultipartForm()
        if err != nil {
            c.String(http.StatusBadRequest, "Form error: %s", err.Error())
            return
        }

        files := form.File["files"] // 获取多个文件
        for _, file := range files {
            // 检查文件类型 (仅允许 image/png)
            mimeType := file.Header.Get("Content-Type")
            if mimeType != "image/png" {
                c.String(http.StatusBadRequest, "Invalid file type: %s for file: %s. Only PNG images are allowed.", mimeType, file.Filename)
                return
            }

            // 保存文件到目标路径
            dst := filepath.Join("./uploads", file.Filename)
            if err := c.SaveUploadedFile(file, dst); err != nil {
                c.String(http.StatusInternalServerError, "Could not save file: %s. Error: %s", file.Filename, err.Error())
                return
            }

            fmt.Printf("Uploaded file: %s\n", file.Filename)
        }

        c.String(http.StatusOK, "All files uploaded successfully")
    })

路由分组

在 Gin 框架中,路由分组(Route Group)是用于组织和管理路由的功能。通过路由分组,可以为一组路由添加公共的前缀、中间件或配置,从而提高代码的可读性和可维护性。

go 复制代码
package main

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

func main() {
	// 1.创建路由
	r := gin.Default()
	// 2.绑定路由规则,执行的函数
	// gin.Context,封装了request和response
	// 用户路由组
	userGroup := r.Group("/user")
	{
		userGroup.GET("/login", login)
		userGroup.GET("/settings", func(c *gin.Context) {
			c.JSON(200, gin.H{"message": "User Settings"})
		})
	}

	// 管理员路由组
	adminGroup := r.Group("/admin")
	{
		adminGroup.GET("/dashboard", func(c *gin.Context) {
			c.JSON(200, gin.H{"message": "Admin Dashboard"})
		})
		adminGroup.GET("/reports", func(c *gin.Context) {
			c.JSON(200, gin.H{"message": "Admin Reports"})
		})
	}
	// 404
	r.NoRoute(func(c *gin.Context) {
		c.String(http.StatusNotFound, "404 not found !!!!")
	})

	// 3.监听端口,默认在8080
	// Run("里面不指定端口号默认为8080")
	r.Run(":8000")
}

func login(c *gin.Context) {
	name := c.DefaultQuery("name", "jack")
	c.JSON(200, gin.H{"name": name})
}




数据解析和绑定

  1. JSON数据解析和绑定的基本步骤

(1) 定义结构体

定义一个与 JSON 数据格式匹配的 Go 结构体。

(2) 使用 c.BindJSONc.ShouldBindJSON

  • c.BindJSON 会在绑定失败时返回错误并终止请求。
  • c.ShouldBindJSON 返回错误但不会中断后续处理,适合灵活的错误处理场景。

(3) 使用结构体处理数据

通过绑定的结构体直接访问解析后的字段。

go 复制代码
package main

import (
    "net/http"

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

type User struct {
    Name  string `json:"name" binding:"required"` // 必填字段
    Age   int    `json:"age" binding:"required"`  // 必填字段
    Email string `json:"email"`                  // 可选字段
}

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

    r.POST("/user", func(c *gin.Context) {
        var user User
        if err := c.ShouldBindJSON(&user); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, gin.H{
            "message": "User data received",
            "user":    user,
        })
    })

    r.Run(":8080")
}

Gin 提供了 binding 标签,用于对字段进行验证。支持多种验证规则。

go 复制代码
type User struct {
    Name  string `json:"name" binding:"required,min=3"` // 必填,最小长度 3
    Age   int    `json:"age" binding:"required,gte=1"`  // 必填,必须大于等于 1
    Email string `json:"email" binding:"required,email"` // 必填,必须是合法邮箱
}
验证规则 含义
required 必须提供该字段
min 字符串或切片的最小长度
max 字符串或切片的最大长度
gte 数字或时间的值必须大于等于指定值
lte 数字或时间的值必须小于等于指定值
email 必须是有效的邮箱地址

  1. 表单数据:
    为字段添加多种绑定方式的标签,例如 jsonform 标签。

Gin 会根据 Content-Type 自动选择适合的绑定方式:

  • 如果是 application/json,则绑定 JSON 数据。
  • 如果是 application/x-www-form-urlencodedmultipart/form-data,则绑定表单数据。
go 复制代码
type User struct {
    Name  string `json:"name" form:"name" binding:"required"` // 必填字段
    Age   int    `json:"age" form:"age" binding:"required,gte=0"`
    Email string `json:"email" form:"email"`
}
  1. URI数据

通过 c.Param 获取路径参数的值

go 复制代码
package main

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

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

    r.GET("/user/:id", func(c *gin.Context) {
        id := c.Param("id") // 提取路径参数
        c.JSON(http.StatusOK, gin.H{
            "user_id": id,
        })
    })

    r.Run(":8080")
}

Gin 提供了 ShouldBindUri 方法,可以将路径参数直接绑定到结构体中,方便处理和验证。

go 复制代码
package main

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

type UserRequest struct {
    ID string `uri:"id" binding:"required"` // 使用 `uri` 标签定义路径参数
}

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

    r.GET("/user/:id", func(c *gin.Context) {
        var req UserRequest
        // 将路径参数绑定到结构体
        if err := c.ShouldBindUri(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, gin.H{
            "user_id": req.ID,
        })
    })

    r.Run(":8080")
}
  1. 路径参数可以和查询参数或表单参数结合使用。Gin 支持同时解析这些参数。
go 复制代码
package main

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

type UserRequest struct {
    ID   string `uri:"id" binding:"required"`  // 路径参数
    Name string `form:"name"`                 // 查询参数或表单参数
}

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

    r.GET("/user/:id", func(c *gin.Context) {
        var req UserRequest

        // 绑定路径参数
        if err := c.ShouldBindUri(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        // 绑定查询参数
        if err := c.ShouldBindQuery(&req); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, gin.H{
            "user_id": req.ID,
            "name":    req.Name,
        })
    })

    r.Run(":8080")
}
go 复制代码
GET /user/123?name=Alice

gin中间件

在 Gin 中,中间件是一个可以插入到请求处理流程中的函数,用于实现请求前后的通用逻辑。例如,认证、日志记录、跨域处理等都可以通过中间件实现。

  1. 中间件定义
go 复制代码
func(c *gin.Context) {
    // 执行逻辑
    c.Next() // 调用后续处理函数
    // 执行逻辑
}

c.Next():调用下一个中间件或处理程序。
c.Abort():停止执行后续的中间件和处理程序。

  1. 全局中间件

全局中间件会应用到所有路由,使用 r.Use() 注册。

go 复制代码
package main

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

func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 请求前逻辑
		fmt.Println("Request URL:", c.Request.URL.Path)

		c.Next() // 执行后续处理

		// 请求后逻辑
		fmt.Println("Response Status:", c.Writer.Status())
	}
}

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

	// 注册全局中间件
	r.Use(Logger())

	r.GET("/ping", func(c *gin.Context) {
		fmt.Println("=======11111111")
		c.String(200, "pong")
	})

	r.Run(":8080")
}

控制台输出:

cmd 复制代码
Request URL: /ping
=======11111111
Response Status: 200

流程:中间件逻辑=》遇到next方法后,执行路由func=》中间件后面的逻辑。

  1. 局部中间件

局部中间件只应用于特定路由或路由组。

go 复制代码
package main

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

func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token != "valid-token" {
			c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
			return
		}
		c.Next()
	}
}

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

	// 局部中间件
	r.GET("/secure", AuthRequired(), func(c *gin.Context) {
		c.JSON(200, gin.H{"message": "Authorized"})
	})

	r.Run(":8080")
}

相关推荐
刀法如飞2 天前
一款Go语言Gin框架MVC脚手架,满足大部分场景
go·mvc·gin
花酒锄作田3 天前
Gin 框架中的规范响应格式设计与实现
golang·gin
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
SunnyRivers3 天前
LangChain中间件详解
中间件·langchain
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs