Gin从入门到精通 (五)数据绑定与验证

数据绑定与验证

数据绑定是指将请求数据(如 JSON、表单、URL 参数等)绑定到 Go 语言中的结构体。Gin 提供了便捷的方法将请求中的数据映射到预定义的结构体字段上,使得开发者可以像访问结构体字段一样访问请求数据。

数据验证是对绑定到结构体上的数据进行检查,确保数据符合特定规则或格式。例如,确保邮箱字段是有效的邮箱格式、年龄字段是一个合法的数字等。

1.数据验证

1.1常见字段

Gin 支持多种常见的验证规则,验证是通过结构体字段中的 binding 标签来进行的。

常用的验证规则:

  • required: 字段必须存在且不为空
  • min、max:对于整数类型的字段,可以使用 minmax 来设置最小值和最大值
  • email: 字段必须是有效的电子邮件地址

required:必填
确保字段不能为空。

Name string `json:"name" binding:"required"`

email:电子邮件格式
确保字段为有效的电子邮件格式。

Email string `json:"email" binding:"required,email"`

min, max:最小值与最大值
对于整数类型的字段,可以使用 minmax 来设置最小值和最大值。

Age int `json:"age" binding:"min=18,max=100"`

len:字符串长度
确保字符串的长度符合指定的范围。

Name string `json:"name" binding:"len=5"`

alpha:只包含字母
确保字段值只包含字母字符。

Code string `json:"code" binding:"alpha"`

alphanum:只包含字母和数字
确保字段值只包含字母和数字。

Username string `json:"username" binding:"alphanum"`

2.处理验证错误

在 Gin 中,数据验证错误通常会作为一个 error 被返回。你可以通过检查 ShouldBindShouldBindJSON 的返回值来捕获错误。

r.POST("/submit", func(c *gin.Context) {
    var user User

    if err := c.ShouldBindJSON(&user); err != nil {
        // 捕获并返回详细的验证错误信息
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		
		/*
		// 或者自定义错误信息
		 c.JSON(http.StatusBadRequest, gin.H{
        "error": "Validation failed: Name is required and Email must be valid",
    })
		*/
		
        return
    }

    c.JSON(http.StatusOK, gin.H{"message": "Data is valid"})
})

2.数据绑定

2.1 Uri参数绑定

在 Gin 中,ShouldBindUri 方法用于从 URL 路径中提取并绑定参数。路径中的动态参数(即 :param)会被提取并绑定到结构体的相应字段。

假设我们有以下 URL 路径:/:name/:id,我们需要将nameid 从 URL 中提取并绑定到结构体

package main

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

type User struct {
	ID   string `uri:"id" binding:"required"`
	Name string `uri:"name" binding:"required"`
}

func main() {
	route := gin.Default()
	route.GET("/:name/:id", func(c *gin.Context) {
		var user User
		if err := c.ShouldBindUri(&user); err != nil {
			c.JSON(400, gin.H{"msg": err.Error()})
			return
		}
		c.JSON(200, gin.H{"name": user.Name, "uuid": user.ID})
	})
	route.Run(":8080")
}

使用 c.ShouldBindUri() 方法从 URL 路径中提取 nameid 参数并绑定到 User 结构体。

binding:"required" 确保 id和name 参数是必填的

使用postman测试:

在这里插入图片描述

2.2 查询参数绑定

ShouldBindQuery 用于将 URL 查询参数(即 ?key=value)绑定到结构体的字段中。查询参数通常用于过滤或分页等操作。

package main

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

type SearchQuery struct {
	Name string `form:"name" binding:"required"`
	Age  int    `form:"age" binding:"required,min=18"`
}

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

	r.GET("/search", func(c *gin.Context) {
		var query SearchQuery
		// 使用 ShouldBindQuery 从查询字符串中绑定参数
		if err := c.ShouldBindQuery(&query); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "Search successful", "query": query})
	})

	r.Run(":8080")
}

使用 c.ShouldBindQuery() 方法将 URL 中的查询参数(如 nameage)绑定到结构体字段。

binding:"required" 确保 nameage 字段必须提供,且 age 必须大于等于 18。

请求路径:

http://localhost:8080/search?name=John&age=30

返回数据:

{"message":"Search successful","query":{"Name":"John","Age":30}}

2.3 JSON 数据绑定

当客户端以 JSON 格式发送数据时,在 Gin 中可以使用 c.ShouldBindJSON 方法将 JSON 数据绑定到 Go 结构体上。

package main

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

type User struct {
	Name string `json:"name" binding:"required"` 
	Email string `json:"email" binding:"required,email"`
}

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

	r.POST("/user", func(c *gin.Context) {
		var user User

		// 绑定 JSON 数据
		if err := c.ShouldBindJSON(&user); err != nil {
			// 数据绑定失败,返回 400 错误
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 数据验证通过,返回成功响应
		c.JSON(http.StatusOK, gin.H{"message": "User created successfully", "user": user})
	})

	r.Run(":8080")
}


使用 c.ShouldBindJSON() 将请求体中的 JSON 数据绑定到 User 结构体中。

我们使用 binding:"required"binding:"email" 来为 NameEmail 字段定义验证规则,确保 Name 必填且 Email 必须是一个有效的邮箱。

使用postman测试:
在这里插入图片描述

2.4 表单数据绑定

gin 通过 ShouldBind() 方法可以将 HTML 表单中的数据绑定到结构体字段上。

package main

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

type User struct {
	Name string `form:"name" binding:"required"`
	Age  int    `form:"age" binding:"required,min=18"`
}

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

	r.POST("/submit", func(c *gin.Context) {
		var user User

		// 绑定表单数据
		if err := c.ShouldBind(&user); err != nil {
			// 数据绑定失败,返回 400 错误
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 数据验证通过,返回成功响应
		c.JSON(http.StatusOK, gin.H{"message": "Form submitted successfully", "user": user})
	})

	r.Run(":8080")
}


使用 c.ShouldBind() 可以将 HTML 表单中的数据绑定到 User 结构体。

使用 binding:"required" 来确保 NameAge 字段是必填项,同时用 min=18 验证 Age 字段的值必须大于等于 18。

使用postman测试:
在这里插入图片描述

当age值小于18时,返回结果如下:

{"error":"Key: 'User.Age' Error:Field validation for 'Age' failed on the 'min' tag"}

2.5 map参数绑定

Gin 目前没有直接支持将 URL 查询参数中的 map 形式绑定到结构体的 map 字段上。不过,可以通过自定义绑定逻辑来实现这个功能。以下是一个示例:

package main

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

// User 结构体,包含一个 map 字段
type User struct {
	UserMap map[string]string
}

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

	r.GET("/userMap/", func(ctx *gin.Context) {
		var user User
		user.UserMap = make(map[string]string)

		// 手动解析查询参数
		values, _ := url.ParseQuery(ctx.Request.URL.RawQuery)
		for key, value := range values {
			if strings.HasPrefix(key, "user[") && strings.HasSuffix(key, "]") {
				// 提取 map 的键
				start := strings.Index(key, "[") + 1
				end := strings.Index(key, "]")
				mapKey := key[start:end]
				user.UserMap[mapKey] = value[0]
			}
		}

		ctx.JSON(200, user)
	})

	r.Run(":8080")
}


在上述代码中,我们手动解析 URL 查询参数,提取出以 user[ 开头,] 结尾的键值对,并将其存储到 User 结构体的 UserMap 字段中。这样就实现了将 URL 查询参数中的 map 形式绑定到结构体的 map 字段上的功能

执行url:
http://localhost:8080/userMap?user[jay]=Beijing&user[jake]=shanghai

返回数据:

{
    "UserMap": {
        "jake": "shanghai",
        "jay": "Beijing"
    }
}

2.6 请求头绑定

ShouldBindHeader 用于将请求头中的数据绑定到结构体字段上。HTTP 请求头包含了请求的元数据,如用户代理、认证信息、内容类型等。

package main

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

type RequestHeaders struct {
	ContentType string `header:"Content-Type" binding:"required"`
	UserAgent   string `header:"User-Agent" binding:"required"`
	Name        string `header:"Name" binding:"required"`
	Email       string `header:"Email" `
}

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

	r.GET("/headers", func(c *gin.Context) {
		var headers RequestHeaders
		// 使用 ShouldBindHeader 从请求头中绑定参数
		if err := c.ShouldBindHeader(&headers); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "Headers received", "headers": headers})
	})

	r.Run(":8080")
}

使用 c.ShouldBindHeader() 方法将请求头中的 Content-TypeUser-Agent 和自定义两个字的NameEmail数据绑定到 RequestHeaders 结构体的字段。

测试请求:
在这里插入图片描述

2.7 自动选择绑定方法

ShouldBind 是一个通用方法,它会根据请求的内容类型自动选择合适的绑定方法(JSON、表单、URL 参数等)。如果请求是 JSON 格式,ShouldBind 会自动调用 ShouldBindJSON;如果是表单或查询参数格式,则会调用相应的绑定方法。

package main

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

type User struct {
    Name  string `json:"name" form:"name" binding:"required"`
    Email string `json:"email" form:"email" binding:"required,email"`
}

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

    r.POST("/submit", func(c *gin.Context) {
        var user User
        // 自动选择绑定方法:JSON、表单或查询参数
        if err := c.ShouldBind(&user); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

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

    r.Run(":8080")
}

json请求数据

{
  "name": "clown",
  "email": "clown95@qq.com"
}

表单请求数据

name=clown&email=clown95@qq.com

XML请求数据

<User>
    <Name>clown</Name>
    <Email>clown95@qq.com</Email>
</User>

最终结果都成功返回数据:

 {
    "message": "Data received",
    "user": {
        "name": "clown",
        "email": "clown95@qq.com"
    }
}

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

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

相关文章

计算机毕业设计SpringBoot+Vue.jst网上超市系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【论文解读】《Training Large Language Models to Reason in a Continuous Latent Space》

论文链接 1. 背景与动机 语言空间与推理的矛盾 目前大多数大语言模型&#xff08;LLMs&#xff09;在解决复杂问题时采用链式思维&#xff08;Chain-of-Thought, CoT&#xff09;方法&#xff0c;即利用自然语言逐步推导出答案。然而&#xff0c;论文指出&#xff1a; 自然语言…

DevEco Studio常用快捷键以及如何跟AndroidStudio的保持同步

DevEco Studio快捷键 DevEco Studio是华为推出的用于开发HarmonyOS应用的集成开发环境&#xff0c;它提供了丰富的快捷键以提高开发效率&#xff0c;以下为你详细介绍不同操作场景下的常用快捷键&#xff1a; 通用操作快捷键 操作描述Windows/Linux 快捷键Mac 快捷键打开设置窗…

4. MySQL 逻辑架构说明

4. MySQL 逻辑架构说明 文章目录 4. MySQL 逻辑架构说明1. 逻辑架构剖析1.1 服务器处理客户端请求1.2 Connectors(连接器)1.3 第1层&#xff1a;连接层1.4 第2层&#xff1a;服务层1.5 第3层&#xff1a;引擎层1.6 存储层 2. SQL执行流程2.1 MySQL 中的 SQL 执行流程 2.2 MySQL…

基于 Python Django 的校园互助平台(附源码,文档)

博主介绍&#xff1a;✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不…

【CVPR2024-工业异常检测】PromptAD:与只有正常样本的少样本异常检测的学习提示

代码链接 摘要 摘要写作总结&#xff1a; 1.提出 两个关键点 &#xff08;视觉语言模型【模型】 少量工业异常检测【方向】&#xff09; 2.想要解决的问题 3.针对上述问题&#xff0c;本文提出了一种什么【方法】的什么【应用方面】方法【模型名】 4.具体讲方法的步骤 5.实验…

WPF框架学习

WPF 可以想winfrom 那样在cs文件修改 属性数据&#xff1b; 为了前后端分离 而解耦合&#xff0c;有了M-V-VM模式 常见框架有 MVVMlight / Prism 等 ------------------------------------------------------------------------------------- 一、前提&#xff1a;有一定基…

网络运维学习笔记 017 HCIA-Datacom综合实验01

文章目录 综合实验1实验需求总部特性 分支8分支9 配置一、 基本配置&#xff08;IP二层VLAN链路聚合&#xff09;ACC_SWSW-S1SW-S2SW-Ser1SW-CoreSW8SW9DHCPISPGW 二、 单臂路由GW 三、 vlanifSW8SW9 四、 OSPFSW8SW9GW 五、 DHCPDHCPGW 六、 NAT缺省路由GW 七、 HTTPGW 综合实…

git,bash - 从一个远端git库只下载一个文件的方法

文章目录 git,bash - 从一个远端git库只下载一个文件的方法概述笔记写一个bash脚本来自动下载get_github_raw_file_from_url.shreanme_file.shfind_key_value.sh执行命令 END git,bash - 从一个远端git库只下载一个文件的方法 概述 github上有很多大佬上传了电子书库&#xf…

【废物研究生零基础刷算法】DFS与递归(一)典型题型

文章目录 跳台阶递归实现指数级枚举递归实现排列型枚举上面两题总结 递归实现组合型枚举P1036选数 跳台阶 思路&#xff1a; 如果 n 1&#xff0c;只有一种走法&#xff08;走 1 级&#xff09;。如果 n 2&#xff0c;有两种走法&#xff08;11 或 2&#xff09;。对于 n &g…

Java-01-源码篇-04集合-05-ConcurrentHashMap(1)

1.1 加载因子 加载因子&#xff08;Load Factor&#xff09;是用来决定什么时候需要扩容的一个参数。具体来说&#xff0c;加载因子 当前元素数量 / 桶的数量&#xff0c;当某个桶的元素个数超过了 桶的数量 加载因子 时&#xff0c;就会触发扩容。 我们都知道 ConcurrentHas…

AI赋能的未来城市:如何用智能化提升生活质量?

这会是我们憧憬的未来城市吗&#xff1f; 随着技术的不断进步和城市化进程的加速&#xff0c;现代城市面临着诸多挑战——交通拥堵、环境污染、能源消耗、人口老龄化等问题愈发突出。为了应对这些挑战&#xff0c;建设智慧城市已成为全球发展的重要趋势。在这一进程中&#xf…

DeepSeek各模型现有版本对比分析

文章目录 一、基础模型系列&#xff1a;V1 到 V3 的演进二、专用模型系列&#xff1a;推理与多模态三、版本选型与商业化趋势 DeepSeek作为最近特别火爆的模型&#xff0c;本文将对DeepSeek现有的主要版本进行对比分析,涵盖参数规模、训练数据、功能改进、应用场景和性能表现等…

【亲测有效】百度Ueditor富文本编辑器添加插入视频、视频不显示、和插入视频后二次编辑视频标签不显示,显示成img标签,二次保存视频被替换问题,解决方案

【亲测有效】项目使用百度Ueditor富文本编辑器上传视频相关操作问题 1.百度Ueditor富文本编辑器添加插入视频、视频不显示 2.百度Ueditor富文本编辑器插入视频后二次编辑视频标签不显示&#xff0c;在编辑器内显示成img标签&#xff0c;二次保存视频被替换问题 问题1&#xff1…

hot100_108. 将有序数组转换为二叉搜索树

hot100_108. 将有序数组转换为二叉搜索树 思路 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#…

RFID涉密载体柜:智能安全,全程守护,提供智能化的安全管控

行业背景 RFID智能载体柜&#xff08;DW-G101&#xff09;是一种便捷化的载体管控系统&#xff0c;它采用RFID技术实现信息化&#xff0c;可以大大提高载体管理的效率和准确性。 随着信息化的快速发展&#xff0c;涉密载体&#xff08;如文件、U盘、光盘等&#xff09;的管理…

【复习】计算机网络

网络模型 OSI 应用层&#xff1a;给应用程序提供统一的接口表示层&#xff1a;把数据转换成兼容另一个系统能识别的格式会话层&#xff1a;负责建立、管理、终止表示层实体之间的通信会话传输层&#xff1a;负责端到端的数据传输网络层&#xff1a;负责数据的路由、转发、分片…

多线程篇学习面试

多线程 1.乐观锁、CAS思想 java乐观锁机制&#xff1a; ​ 乐观锁体现的是悲观锁的反面。它是一种积极的思想&#xff0c;它总是认为数据是不会被修改的&#xff0c;所以是不会对数据上锁的。但是乐观锁在更新的时候会去判断数据是否被更新过。乐观锁的实现方案一般有两种&a…

Spring Boot 概要(官网文档解读)

Spring Boot 概述 Spring Boot 是一个高效构建 Spring 生产级应用的脚手架工具&#xff0c;它简化了基于 Spring 框架的开发过程。 Spring Boot 也是一个“构件组装门户”&#xff0c;何为构件组装门户呢&#xff1f;所谓的“构件组装门户”指的是一个对外提供的Web平台&#x…

计算机毕业设计SpringBoot+Vue.jst0甘肃非物质文化网站(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…