Gin框架基础

1、一个简单的Gin示例

下载并安装Gin:

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

1.1 一个简单的例子

package main

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


func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()

	// 当客户端以GET方式访问 /hello 时,会执行后面的匿名函数,返回Hello World
	r.GET("/hello", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "Hello World")
	})

	r.GET("/json", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "Hello World",
		})
	})

	// 在8080端口监听
	r.Run(":8080")
}

使用浏览器打开127.0.0.1:8080/hello就能看到一串字符串,打开127.0.0.1:8080/json就能看到一串JSON字符串。
在这里插入图片描述

1.2 RESTful API

Gin 如何处理 GET, POST, PUT, PATCH, DELETE 和 OPTIONS 请求
Gin 处理各种 HTTP 请求是非常简单的,只要使用 router.XXX 方法即可注册处理器。其中 XXX 是 HTTP 请求方法的大写模式。

也就是说,Gin框架支持开发RESTful API的开发。
在这里插入图片描述

package main

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


func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()

	//
	r.GET("/book", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "GET",
		})
	})

	r.POST("/book", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "POST",
		})
	})

	r.PUT("/book", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "PUT",
		})
	})
	
	r.DELETE("/book", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "DELETE",
		})
	})

	// 在8080端口监听
	r.Run(":8080")
}

开发RESTful API的时候我们通常使用Postman来作为客户端的测试工具。

在这里插入图片描述

2、获取参数

2.1、如何获取 GET 查询字符串参数?

查询字符串参数就是 URL 中 ? 后面 # 之前的参数,比如下面的 URL,
https://www.xxxxx.cn/user/search?username=金克斯&address=艾欧尼亚#reply0
查询字符串参数特指 username=金克斯&address=艾欧尼亚

Gin 的 Handler 提供了 以下几种方式

方法说明
ctx.Query()获取查询参数,如果参数不存在或值为空则返回空字符串 “”
ctx.DefaultQuery()获取查询参数,如果参数不存在或值为空则返回第二个参数做为值
ctx.GetQuery()类似于 c.Query(),但同时返回第二个 bool 参数用于判断该参数到底存不存在
  1. ctx.Query()
ctx.Query("username")	// 返回"金克斯"
ctx.Query("address")	// 返回"艾欧尼亚"
ctx.Query("gender")		// 返回""
  1. ctx.DefaultQuery()
ctx.DefaultQuery("username", "none")	// 返回"金克斯"
ctx.DefaultQuery("address", "none")		// 返回"艾欧尼亚"
ctx.DefaultQuery("gender", "none")		// 返回"none"
  1. ctx.GetQuery()
ctx.GetQuery("username")	// 返回("金克斯", true)
ctx.GetQuery("address") 	// 返回("艾欧尼亚", true)
ctx.GetQuery("gender")		// 返回("", false)

例子

package main

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


func main() {
	// 创建一个默认的路由引擎
	router := gin.Default()

	// 解析/user/search?username=金克斯&address=艾欧尼亚#reply0
	router.GET("/user/search", func(ctx *gin.Context) {
		username := ctx.Query("username")
		address, _ := ctx.GetQuery("address")
		gender := ctx.DefaultQuery("gender", "none")

		ctx.JSON(http.StatusOK, gin.H{
			"username": username,
			"address": address,
			"gender": gender,
		})
	})


	// 在8080端口监听
	router.Run(":8080")
}

浏览器返回http://127.0.0.1:8080/user/search?username=金克斯&address=艾欧尼亚#reply0,返回

{"address":"艾欧尼亚","gender":"none","username":"金克斯"}

2.2、如何获取 POST 表单form数据

Gin 提供了三个类似的方法用于获取 POST 请求提交的参数

方法说明
ctx.PostForm()获取 POST 表单参数,如果参数不存在或值为空则返回空字符串 “”
ctx.DefaultPostForm()获取 POST 表单参数,如果参数不存在或值为空则返回第二个参数做为值
ctx.GetPostForm()类似于 c.PostForm(),但同时返回第二个 bool 参数用于判断该参数到底存不存在
package main

import (
	"net/http"

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


func main() {
	// 创建一个默认的路由引擎
	router := gin.Default()

	// 解析/user/search?username=金克斯&address=艾欧尼亚#reply0
	router.POST("/user/search", func(ctx *gin.Context) {
		username := ctx.PostForm("username")
		address, _ := ctx.GetPostForm("address")
		gender := ctx.DefaultPostForm("gender", "none")

		ctx.JSON(http.StatusOK, gin.H{
			"username": username,
			"address": address,
			"gender": gender,
		})
	})


	// 在8080端口监听
	router.Run(":8080")
}

使用postman发送表单请求
在这里插入图片描述

2.3、如何同时获取 GET 数据和 POST 数据

package main

import (
	"net/http"

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

func main() {

	router := gin.Default()

	router.POST("user/search", func(ctx *gin.Context) {
		query_name := ctx.Query("name")
		query_address := ctx.Query("address")

		post_name := ctx.PostForm("name")
		post_address := ctx.PostForm("address")

		ctx.JSON(http.StatusOK, gin.H{
			"query_name": query_name,
			"query_address": query_address,
			"post_name": post_name,
			"post_address": post_address,
		})
	})

	router.Run(":8080")
	
}

在这里插入图片描述

2.4、如何获取路由参数

在没有路由参数之前,如果我们想获取/user/1/user/2的用户数据,我们需要注册多个路由器

router.GET("/user/1", func(c *gin.Context) {})
router.GET("/user/2", func(c *gin.Context) {})

如果用户量大了,这个注册显然不靠谱。

Gin 允许我们使用 :[参数名] *[参数名] 来注册一个路由参数,比如上面的用户详情就可以注册为 /user/:user_id。然后我们就可以在路由 Handler 中通过 c.Param("user_id")获取到这个参数。

  • :[参数名] :路由参数能够匹配任何字符串,除了路径分隔符 /。 也就是说 /user/:user_id 可以匹配 /user/1 但不能匹配 /user/1/message
	router.GET("/user/:name", func(ctx *gin.Context) {
		name := ctx.Param("name")
		ctx.JSON(http.StatusOK, gin.H{
			"message": name,
		})
	})

	/*
		127.0.0.1:8080/user/金克斯, 返回 {"message":"金克斯"}
		127.0.0.1:8080/user/金克斯/艾欧尼亚, 返回 404 page not found
	*/
  • *[参数名] :路由参数可以匹配任意字符,包括/,也就是说 /user/:user_id 可以匹配 /user/1 也可以能匹配 /user/1/message ,还能匹配 /user/1/message/a/b/c/d/e
	router.GET("/user/:name/*address", func(ctx *gin.Context) {
		name := ctx.Param("name")
		address := ctx.Param("address")

		ctx.JSON(http.StatusOK, gin.H{
			"message": name,
			"address": address,
		})
	})

	/*
		127.0.0.1:8080/user/金克斯, 返回 {"address":"/","message":"金克斯"}
		127.0.0.1:8080/user/金克斯/艾欧尼亚, 返回 {"address":"/艾欧尼亚","message":"金克斯"}
	*/

Gin 的路由定义遵循几个规范

  • 和访问路径一样的路由定义(精确路由) 将会被优先匹配。 比如
	router.GET("/user/:name", func(ctx *gin.Context) {
		name := ctx.Param("name")
		ctx.JSON(http.StatusOK, gin.H{
			"message": name,
		})
	})
	// 精确路由(相对于有路由参数的路由)会被优先匹配,而无论他们在哪里定义
    router.GET("/user/groups", func(c *gin.Context) {
        c.String(http.StatusOK, "The available groups are [...]")
    })
  • 默认情况下,如果先定义的路由匹配了,那么后续定义的路由就不会被匹配。

2.5、如何接受表单中的字典(Map)参数

Gin 提供了 ctx.QueryMap() 用于获取字典形式的查询字符串参数,提供了ctx.PostFormMap()用于获取字典形式的 POST 表单参数。

package main

import (
	"net/http"

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

func main() {

	router := gin.Default()

	router.POST("/post", func(ctx *gin.Context) {
		ids := ctx.QueryMap("ids")
		names := ctx.PostFormMap("names")

		ctx.JSON(http.StatusOK, gin.H{
			"ids": ids,
			"names": names,
		})

	})
	router.Run(":8080")

}

在这里插入图片描述

2.6、如何对请求参数模型绑定和验证

为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryStringform表单JSONXML等参数到结构体中。
原理都是一样的: 需要在要绑定的所有字段上,设置相应的 tag。例如,使用 JSON 绑定时,设置字段标签为 json:"fieldname"

Gin 框架提供了两类绑定方法:

  • 第一类: 必须绑定 (Must Bind),BindXXX() 方法,如果绑定出错则会直接抛出 400 错误:
    方法有: Bind(), BindJSON(), BindXML(), BindQuery(), BindYAML(), BindHeader(), BindTOML()。

  • 第二类: 应该绑定 (Should bind),ShouldBindXXX() 等方法,如果绑定出错则会抛出异常
    方法有: ShouldBind(), ShouldBindJSON(), ShouldBindXML(), ShouldBindQuery(), ShouldBindYAML(), ShouldBindHeader(), ShouldBindTOML(),

这些方法具体的实现调用了 ShouldBindWith()。 如果发生绑定错误,Gin 会返回错误并由开发者处理错误和请求。

package main

import (
	"net/http"

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

type Login struct {
	Username string `form:"username" json:"username" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

func main() {

	router := gin.Default()

	// 绑定JSON的示例 ({"username": "admin", "password": "123456"})
	router.POST("/loginJson", func(ctx *gin.Context) {
		var login Login
		// ShouldBind()会根据请求的Content-Type自行选择绑定器
		if err := ctx.ShouldBind(&login); err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if login.Username == "admin" && login.Password == "123456" {
			ctx.JSON(http.StatusOK, gin.H{
				"status":   "you are logged in",
				"username": login.Username,
				"password": login.Password,
			})
		} else {
			ctx.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
		}

	})

	// 绑定form表单示例
	router.POST("/loginForm", func(ctx *gin.Context) {
		var login Login
		// ShouldBind()会根据请求的Content-Type自行选择绑定器
		if err := ctx.ShouldBind(&login); err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if login.Username == "admin" && login.Password == "123456" {
			ctx.JSON(http.StatusOK, gin.H{
				"status":   "you are logged in",
				"username": login.Username,
				"password": login.Password,
			})
		} else {
			ctx.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
		}
	})

	// 绑定QueryString示例
	router.GET("loginQuery", func(ctx *gin.Context) {
		var login Login
		// ShouldBind()会根据请求的Content-Type自行选择绑定器
		if err := ctx.ShouldBind(&login); err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if login.Username == "admin" && login.Password == "123456" {
			ctx.JSON(http.StatusOK, gin.H{
				"status":   "you are logged in",
				"username": login.Username,
				"password": login.Password,
			})
		} else {
			ctx.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
		}
	})

	router.Run(":8080")

}

绑定JSON
在这里插入图片描述
绑定form表单
在这里插入图片描述
绑定QueryString
在这里插入图片描述
需要注意的是,如果没有输入password,是会报错的。是因为tag中的binding:"required"进行了限制。如果将 Password 改为 binding:"-", 再次运行上面的示例就不会返回错误。

Password string `form:"password" json:"password" binding:"required"`

参考资料

李文周的博客
Gin 框架中文文档

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

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

相关文章

昇思25天学习打卡营第10天 | 基于MindNLP+MusicGen生成自己的个性化音乐

基于MindNLPMusicGen生成自己的个性化音乐 MusicGen是来自Meta AI的Jade Copet等人提出的基于单个语言模型(LM)的音乐生成模型,能够根据文本描述或音频提示生成高质量的音乐样本,相关研究成果参考论文《Simple and Controllable …

C程序设计谭浩强第五版

程序习题 第一章1、第5题2、第6题 第三章1、第2题2、第2题3、第3题4、第4题Tips 第一章 1、第5题 编写一个C程序,运行时输出以下图形: #include <stdio.h> int main() {for (int i 0; i < 4; i) // 输出4行循环控制{for (int j 0; j < i; j) //第几行就输出几…

jenkins中执行docker命令

1. 修改docker.sock文件的所属组 命令如下&#xff1a; sudo chown root:root docker.sock 2. 对这个文件赋予权限&#xff0c;供其他用户使用&#xff0c;给定权限命令如下&#xff1a; sudo chmod orw docker.sock 3. docker容器映射 这里需要两个文件&#xff1a; 一个…

Selenium时间控件的处理

我们经常在做web自动化测试过程中会遇到时间控件&#xff0c;那么对于时间控件如何处理&#xff0c;我们可以来分析下。 对于时间控件一般分为两种&#xff1a; 1、普通的时间控件 直接通过send_keys就可以解决 d.get("https://www.ctrip.com/?sid155952&alliancei…

华三(H3C)交换机堆叠配置

目录 一、相关理论 二、实验需求 三、实验组网 四、具体配置 4.1 堆叠配置 4.2 查看堆叠相关配置 4.3 MAD 检测配置 一、相关理论 H3C的堆叠称为IRF&#xff08;Intelligent Resilient Framework&#xff0c;智能弹性架构&#xff09; IRF中每台设备都称为成员设备。成…

架构师篇-7、企业安全架构设计及实践

摘要&#xff1a; 认识企业安全架构企业安全案例分析及实践 内容&#xff1a; 为什么做企业安全架构怎么做好安全架构设计案例实践分析&随堂练 为什么要做企业安全架构 安全是麻烦制造者&#xff1f; 整天提安全需求增加开发工作增加运维要求增加不确定性延后业务上线…

Datawhale机器学习day-1

赛题 在当今科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的深度和广度渗透到科研领域&#xff0c;特别是在化学及药物研发中展现出了巨大潜力。精准预测分子性质有助于高效筛选出具有优异性能的候选药物。以PROTACs为例&#xff0c;它是…

理想汽车提出3DRealCar:首个大规模3D真实汽车数据集

理想提出3DRealCar&#xff0c;这是第一个大规模 3D 实车数据集&#xff0c;包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar&#xff1a;首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…

基于公有云部署wordpress

云平台选择 腾讯云 阿里云 华为云 项目部署 一、架构讲解 1.1、定义与组成 LNMP是Linux、Nginx、MySQL&#xff08;或MariaDB&#xff09;和PHP&#xff08;或Perl、Python&#xff09;的首字母缩写&#xff0c;代表在Linux系统下使用Nginx作为Web服务器&#xff0c;MySQL作为…

【SGX系列教程】(八)Intel-SGX 官方示例分析(SampleCode)——Seal Unseal

文章目录 一.Seal Unseal原理介绍1.1 Intel SGX supported Sealing Policies 二.源码分析2.1 README2.2 重点代码分析2.2.1 主要代码模块交互流程分析2.2.2 App/App.cpp2.2.3 Enclave_Seal/Enclave_Seal.cpp2.2.4 Enclave_Unseal/Enclave_Unseal.cpp 2.3 总结 三.参考文献四.感…

PMBOK® 第六版 结束项目或阶段

目录 读后感—PMBOK第六版 目录 不论是阶段的收尾还是项目整体的收尾&#xff0c;都应是令人振奋的事。然而&#xff0c;在实际生活中&#xff0c;收尾工作却相当艰难。会遭遇负责人调离、换任&#xff0c;导致不再需要已购产品&#xff1b;项目收尾时对照招标文件或合同&…

基于python的房价多元线性回归分析

1.导入必要的库 import pandas as pd import numpy as np import statsmodels.api as sm from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score import matplotlib.pyplot as plt # 忽略Matplotlib的警告&#xff08;可选&…

SpringBoot实现文章点赞功能

提示&#xff1a;今日是2024年的6月30日&#xff0c;未来的你看到这篇文章&#xff0c;希望你依旧快乐 文章目录 前言 首先在这里前缀部分我就不做要求了,比如说登录信息什么的 数据库表格 这里实现点赞功能&#xff0c;主要是围绕论坛项目完成的 user_info代表用户信息表 for…

20240630每日一题-组合数学-平均分组问题

更多资源请关注纽扣编程微信公众号 将6个小球&#xff0c;其中1个红球&#xff0c;2个黑球&#xff0c;3个白球拍成一列&#xff0c;相同颜色的球没区别&#xff0c;那么有多少种排法&#xff1f; 答案 60种 分析 相同颜色的小球可以看作平均分组&#xff0c;去除对应排序的…

Zookeeper:Zookeeper JavaAPI操作与分布式锁

文章目录 一、Zookeeper JavaAPI操作1、Curator介绍2、创建、查询、修改、删除节点3、Watch事件监听 二、Zookeeper分布式锁原理 一、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkC…

基于PHP的酒店管理系统(改进版)

有需要请加文章底部Q哦 可远程调试 基于PHP的酒店管理系统(改进版) 一 介绍 此酒店管理系统(改进版)基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery插件美化。系统角色分为用户和管理员。系统在原有基础上增加了注册登录注销功能&#xff0c;增加预订房间图片…

临时文件上传系统Plik

什么是 Plik &#xff1f; Plik 是一个基于 Go 语言的可扩展且用户友好的临时文件上传系统&#xff08;类似于 Wetransfer&#xff09;。 软件主要特点&#xff1a; 强大的命令行客户端易于使用的 Web 用户界面多个数据后端&#xff1a;文件、OpenStack Swift、S3、Google Clo…

Swift中的二分查找:全面指南

Swift中的二分查找&#xff1a;全面指南 简介 二分查找是计算机科学中的经典算法&#xff0c;被广泛用于在已排序的数组中高效地搜索目标值。与线性查找逐个检查每个元素不同&#xff0c;二分查找不断将搜索区间减半&#xff0c;因此在处理大数据集时要快得多。 在这篇博客中…

java基于ssm+jsp 固定资产管理系统

1前台首页功能模块 固定资产管理系统&#xff0c;在系统首页可以查看首页、设备信息、论坛信息、我的、跳转到后台等内容&#xff0c;如图1所示。 图1前台首页功能界面图 注册&#xff0c;在注册页面可以填写用户名、密码、姓名、性别、头像、身份证、手机等详细内容&#xff…

基于Ollama Python的本地多模态大模型

0&#xff0c;背景 最近测试Ollama&#xff0c;发现之前直接下载开源模型在我电脑上都跑不动的模型&#xff0c;居然也能运行了&#xff08;AMD 7840HS核显/32GB内存&#xff09;&#xff0c;突发奇想那些多模态大模型能不能基于Python接口使用&#xff0c;所以决定尝试一下。…