【GO基础学习】gin的使用

文章目录

  • 模版使用流程
  • 参数传递
  • 路由分组
  • 数据解析和绑定
  • gin中间件


模版使用流程

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参数。
r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "Hello "+name+"!")
	})

在这里插入图片描述

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类型:

func (c *Context) DefaultQuery(key, defaultValue string) string {
	if value, ok := c.GetQuery(key); ok {
		return value
	}
	return defaultValue
}
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. 表单传值
<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>
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. 文件上传

单个文件:

<form action="http://localhost:8000/upload" method="post" enctype="multipart/form-data">
          上传文件:<input type="file" name="file" >
          <input type="submit" value="提交">
    </form>
// 限制上传文件大小 (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)
    })

多个文件:

// 限制上传文件大小 (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)是用于组织和管理路由的功能。通过路由分组,可以为一组路由添加公共的前缀、中间件或配置,从而提高代码的可读性和可维护性。

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) 使用结构体处理数据

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

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 标签,用于对字段进行验证。支持多种验证规则。

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,则绑定表单数据。
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 获取路径参数的值

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 方法,可以将路径参数直接绑定到结构体中,方便处理和验证。

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 支持同时解析这些参数。
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")
}

GET /user/123?name=Alice

gin中间件

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

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

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

  1. 全局中间件

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

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")
}

控制台输出:

Request URL: /ping
=======11111111
Response Status: 200

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

  1. 局部中间件

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

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")
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945312.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

磁编码器(Magnetic Encoder)

磁编码器&#xff08;Magnetic Encoder&#xff09;是一种传感器&#xff0c;它通过检测磁性材料的磁场变化来测量旋转或线性位置。编写用于读取磁编码器数据的C语言程序时&#xff0c;您需要根据具体的硬件接口和编码器类型进行调整。以下是一个基本的框架&#xff0c;假设我们…

Qt Creator项目构建配置说明

QT安装好之后&#xff0c;在安装目录的Tools\QtCreator\bin下找到qtcreator.exe文件并双击打开 点击文件-新建文件或项目 选择Qt Widgets Application 设置项目名称以及路径 make工具选择qmake&#xff08;cmake还未尝试过&#xff09; 设置主界面对应类的名称、父类&#…

智能边缘计算×软硬件一体化:开启全场景效能革命新征程(企业开发者作品)

边缘智能技术快速迭代&#xff0c;并与行业深度融合。它正重塑产业格局&#xff0c;催生新产品、新体验&#xff0c;带动终端需求增长。为促进边缘智能技术的进步与发展&#xff0c;拓展开发者的思路与能力&#xff0c;挖掘边缘智能应用的创新与潜能&#xff0c;高通技术公司联…

【React】- 跨域PDF预览、下载(改文件名)、打印

我们经常会碰到跨域来方位PDF&#xff0c;同时需要下载、打印的需求&#xff0c;通常由于浏览器的安全策略&#xff0c;可以预览&#xff0c;但是下载和打印可能会受限&#xff0c;这时候怎么办呢&#xff1f; 1.创建一个隐藏的标签 要下载 iframe 中的 PDF 文件&#xff0c;…

Ps:创建数据驱动的图像

在设计实践中&#xff0c;常常需要处理大量内容变化但设计格式统一的任务&#xff0c;例如批量生成名片、工作证、学生证、胸牌、奖状或证书甚至图册。这些工作如果逐一手动制作&#xff0c;不仅耗时费力&#xff0c;还容易出错。 为解决这一问题&#xff0c;Photoshop 提供了强…

Kotlin 协程基础知识总结六 —— 协程 Flow 的综合应用

1、项目描述与搭建 &#xff08;P92~P94&#xff09;我们会将几个 Flow 的应用实例放在同一个 Demo 中&#xff0c;主页就是一个 Activity 里包含一个按钮&#xff0c;点击按钮跳转到对应的功能展示页面上。整体架构采用一个 Activity 多个 Fragment 的结构&#xff0c;结合 J…

环,域,体,整区,理想,极大理想,

环&#xff1a; 定义&#xff1a; 加法交换群 乘法半群 分配律 域的定义&#xff1a; 加法交换群 乘法群&#xff08;去掉0元是交换群&#xff09; 分配律 Eg:比如整数集合不是域&#xff0c;因为对于乘法来说&#xff0c;去掉0后没有单位元了&#xff0c;但是是环 Eg…

关于Flutter应用国际化语言的设置

目录 1. Locale配置 2. 用户切换/启动自动加载缓存里面的locale 由于最近在开发app国际化设置的时候遇到一些问题&#xff0c;所以做出一些总结。 1. Locale配置 具体的初始化配置可以参考文档&#xff1a;i18n | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 值得…

【游戏开发】游戏生产的标准与工业化,管线Pipeline的概念与设计(项目管理,资产管理)

【游戏开发】游戏生产的标准与工业化&#xff0c;管线Pipeline的概念与设计&#xff08;项目管理&#xff0c;资产管理&#xff09; 文章目录 1、管线&#xff08;Pipeline&#xff09;是什么&#xff1f;1.1 管线解决什么问题&#xff08;例子&#xff09;1.2 一个动画电影的完…

探寻 OneCode 核心优势:MVVM 进阶与前后端协同之魅

在当今的软件开发领域&#xff0c;高效、可维护且功能强大的架构是开发者们不懈追求的目标。OneCode 凭借其独特的增强版 MVVM 架构、前后端一体化特性&#xff0c;以及创新的技术如 OneCode DSM&#xff08;Domain-Specific Modeling&#xff0c;领域特定建模&#xff09;、视…

机器人C++开源库The Robotics Library (RL)使用手册(三)

进入VS工程,我们先看看这些功能函数及其依赖库的分布关系: rl命名空间下,主要有八大模块。 搞定VS后将逐个拆解。 1、编译运行 根据报错提示,配置相应错误的库(根据每个人安装位置不同而不同,我的路径如下:) 编译所有,Release版本耗时大约10分钟。 以rlPlan运动…

ISP代理与住宅代理的区别

了解ISP代理 通常称为互联网服务提供商代理&#xff0c;通过服务提供商将用户直接连接到互联网。这些代理利用互联网服务提供商的网络&#xff0c;通常提供广泛的IP地址池。ISP代理通常快速可靠&#xff0c;非常适合一般浏览和常规互联网使用场景。 了解住宅代理 相比之下&a…

【ArcGIS Pro】完整的nc文件整理表格模型构建流程及工具练习数据分享

学术科研啥的要用到很多数据&#xff0c;nc文件融合了时间空间数据是科研重要文件。之前分享过怎样将nc文件处理成栅格后整理成表格。小编的读者还是有跑不通整个流程的&#xff0c;再来做一篇总结篇&#xff0c;也分享下练习数据跟工具&#xff0c;如果还是弄不了的&#xff0…

使用 Navicat 官方免费版来实现从 DAT 文件填充 MySQL 8 表

在异构存储库之间迁移数据&#xff08;即源数据库和目标数据库来自不同供应商的不同数据库管理系统&#xff09;会遇到一些挑战。在某些情况下&#xff0c;可以同时连接两个数据库。但有时根本无法实现。面对这样的困境&#xff0c;数据库从业者别无选择&#xff0c;只能从转储…

Three.js滚动画案例精选

今天为大家带来 3 个基于滚动动画的网站 Demo&#xff0c;它们不仅视觉效果惊艳&#xff0c;而且每个案例的源码都已开源在 GitHub&#xff0c;方便大家学习和借鉴&#xff01; 3D照片墙滚动 通过滚动操作实现 3D 网格效果以及动态过渡动画。这个案例使用了 GSAP 的 SplitTex…

今日收获(C语言)

一.文件的打开 有这样一个结构体&#xff0c;它内部是文件信息区&#xff0c;文件信息区中的变化可以影响到硬盘中的数据。这个结构体的名字是FILE。我们如果想要写代码对文件进行各种操作&#xff0c;就需要一个指向文件信息区的指针&#xff0c;这个指针的类型是FILE*&#…

【C++】九九乘法表编程题详解与多角度对比分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目概述题目描述 &#x1f4af;老师的实现方法代码解析优点不足 &#x1f4af;我的实现方法代码解析优点不足 &#x1f4af;实现方法对比&#x1f4af;优化与扩展代码优化…

RK3568 bsp 9 - USB调试记录

文章目录 1、环境介绍2、RK3568 USB资源介绍3、配置目标4、dts配置4.1、USB3.0 OTG4.2、USB2.0 Host 2 和 USB2.0 Host 3 5、kernel配置5.1、USB PHY CONFIG5.2、USB Host CONFIG5.3、USB OTG CONFIG5.4、USB外设CONFIG5.4.1、Mass Storage Class CONFIG5.4.2、USB HID CONFIG …

图像描述/字幕开源模型与数据集全览

图像描述/字幕&#xff08;Image Captioning&#xff09;是用文字描述图像内容的任务&#xff0c;属于计算机视觉和自然语言处理的交叉领域。大多数图像描述系统采用编码器-解码器&#xff08;encoder-decoder&#xff09;框架&#xff0c;其中输入图像被编码为中间表示形式&am…

mongodb(6.0.15)安装注意事项,重装系统后数据恢复

window10系统 上周重装了系统&#xff0c;环境变量之类的都没有了。现在要恢复。 我电脑里之前的安装包没有删除&#xff08;虽然之前也没在C盘安装&#xff0c;但是找不到了&#xff0c;所以需要重新下载安装&#xff09;&#xff0c;长下图这样。这个不是最新版本&#xff0…