gin 基本使用

2023-09-21 22:41:51

gin 初体验

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

func main() {
  r := gin.Default()
  r.GET("/ping", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
      "message": "pong",
    })
  })
  r.Run()
}

gin 路由接受一个 type HandlerFunc func(Context) 类型的函数

New 和 Default 的区别

gin.New 和 gin.Default 都可以创建一个类型为 *gin.Engine 的 router

他们的区别是,gin.Default 加了两个中间件:Logger(), Recovery()

路由分组

路由分组功能是将相同功能的路由进行分组,方便管理

r := gin.Default()
r.GET("/goods/list", goodList)
r.GET("/goods/1", goodDetail)
r.POST("goods/add", createGood)
func goodList(c *gin.Context)   {}
func goodDetail(c *gin.Context) {}
func createGood(c *gin.Context) {}

r := gin.Default()
goodsGroup := r.Group("/goods")
{
  goodsGroup.GET("/list", goodList)
  goodsGroup.GET("/1", goodDetail)
  goodsGroup.POST("/add", createGood)
}

url 中的变量

要获取 url 中的变量,使用 :xxx 的形式

func main() {
  r := gin.Default()
  goodsGroup := r.Group("/goods")
  {
    goodsGroup.GET("/:id", goodDetail)
  }
  r.Run()
}

func goodDetail(c *gin.Context) {
  id := c.Param("id")
  c.JSON(http.StatusOK, gin.H{
    "message": "id: " + id,
  })
}

这种形式会有一个问题,如果有两个路由,一个是 /goods/list,一个是 /goods/:id,那么 /goods/list 会被 /goods/:id 匹配到
解决办法是使用 goodsGroup.GET(“/list”, goodList),这样就不会有问题了

func main() {
  r := gin.Default()
  goodsGroup := r.Group("/goods")
  {
    goodsGroup.GET("/list", goodList)
    goodsGroup.GET("/:id", goodDetail)
  }
  r.Run()
}

func goodList(c *gin.Context) {
  c.JSON(http.StatusOK, gin.H{
    "message": "list",
  })
}

func goodDetail(c *gin.Context) {
  id := c.Param("id")
  c.JSON(http.StatusOK, gin.H{
    "message": "id: " + id,
  })
}

但是其他路由还是会进入到 /goods/:id 中,比如 /goods/detail

如果只想匹配 id 是数字,需要这样做

通过一个结构体来绑定 uri 中的参数,在注册函数中使用 ShouldBindUri 方法来绑定,如果不是绑定的类型,就返回错误

type Params struct {
	ID int `uri:"id" binding:"required"`
}

func main() {
	r := gin.Default()
	goodsGroup := r.Group("/goods")
	{
		goodsGroup.GET("/:id", goodDetail)
	}

	r.Run()
}
func goodDetail(c *gin.Context) {
	id := c.Param("id")
	var params Params
	if err := c.ShouldBindUri(&params); err != nil {
		c.Status(http.StatusBadRequest)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"message": "id: " + id,
	})
}

还有一种形式是使用 * 来匹配,比如 /goods/*name

如果访问的路由是 /goods/1/2/3/4,那么 id 就是 1,name 就是 /2/3/4,一般用来访问服务器上的文件

goodsGroup.GET("/:id/*name", goodPersoon)
func goodPerson(c *gin.Context) {
  id := c.Param("id")
  name := c.Param("name")
  c.JSON(http.StatusOK, gin.H{
    "id": id,
    "name": name,
  })
}

获取请求中的参数

获取 query 参数,可以使用 c.Query(“key”),如果没有这个参数,就返回空字符串

如果想要获取 query 参数,但是没有这个参数,就返回默认值,可以使用 c.DefaultQuery(“key”, “default”)

page := c.DefaultQuery("page", "1")
size := c.Query("size")

获取 body 参数,可以使用 c.PostForm(“key”),如果没有这个参数,就返回空字符串
如果想要获取 body 参数,但是没有这个参数,就返回默认值,可以使用 c.DefaultPostForm(“key”, “default”)

name := c.DefaultPostForm("name", "default")
age := c.PostForm("age")

PostForm 是针对 Content-Type 是 application/x-www-form-urlencoded 和 application/form-data 的情况
如果请求参数是 application/json,那么需要使用 c.ShouldBindJSON/c.BindJSON 方法来获取参数

type Body struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func goodAdd(c *gin.Context) {
	var body Body
	c.BindJSON(&body)
	c.JSON(http.StatusOK, gin.H{
		"name": body.Name,
		"age":  body.Age,
	})
}

表单验证

表单验证可以直接使用 binding 标签来实现

gin 内置了 validator,文档:validator

注册时,需要输入两次密码,可以使用 eqfield 来验证两次密码是否一致

type SignUpForm struct {
  Age        uint8  `json:"age" binding:"required,gte=1,lte=130"`
  Name       string `json:"name" binding:"required,min=3"`
  Email      string `json:"email" binding:"required,email"`
  Password   string `json:"password" binding:"required"`
  RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
r.POST("/signup", func(c *gin.Context) {
  var signUpFrom SignUpForm
  if err := c.ShouldBindJSON(&signUpFrom); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{
      "error": err.Error(),
    })
    return
  }
  c.JSON(http.StatusOK, gin.H{
    "message": "ok",
  })
})


更多推荐

全国职业技能大赛云计算--高职组赛题卷⑤(容器云)

全国职业技能大赛云计算--高职组赛题卷⑤(容器云)第二场次题目:容器云平台部署与运维任务2基于容器的web应用系统部署任务(15分)任务3基于容器的持续集成部署任务(15分)任务4Kubernetes容器云平台部署与运维(15分,本任务只公布考试范围,不公布赛题)需要环境的可以私信联系博主!!!第二场次题目:容器云平台

android h5 共享停车系统myeclipse开发mysql数据库编程服务端java计算机程序设计

一、源码特点javaandroidh5共享停车系统APP是一套完善的WEB+android设计系统,对理解JSPjava,安卓app编程开发语言有帮助(系统采用web服务端+APP端综合模式进行设计开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。Android平台的共享停车系统1二、功能介绍具体实现如

「Java开发指南」在MyEclipse中的Spring开发(二)

在上文中(点击这里回顾>>),我们主要介绍了一些Spring的基本概念、Spring项目配置及向导,本章节将继续介绍如何管理多个项目,Spring配置编辑器等,欢迎持续关注~MyEclipsev2023.1.2离线版下载(Q技术交流:742336981)4.管理多个Beans和项目除了使用bean配置文件编辑器来管理S

动态代理原理和设计模式详解

一、什么是代理模式代理模式是一种设计模式,提供了对目标对象额外的访问方式,即可以通过代理访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的方式进行访问,扩展目标对象的功能。通俗的说,例如你想租房,房子就是你的目标访问对象,那在中间的信息差巨大的情况下,你想要精准找到合适的房子,那么你可以找到中介,中介就是你的

Selenium基础知识

关于selenium你应该知道的selenium是什么?一个自动化测试的工具(系统测试)测试阶段:单元测试、集成测试、系统测试、验收测试自动化测试属于:系统测试自动测试工具:自动化功能测试工具和自动化性能测试selenium包括什么组件?seleniumide,selenium2(seleniumRC(服务)+webD

单例模式,适用于对象唯一的情景(设计模式与开发实践 P4)

文章目录单例模式实现代理单例惰性单例上一章后续的内容是关于JS函数闭包的,考虑很多读者已经有了闭包基础或者希望通过实战理解,遂跳过上一章直接开始设计模式篇~需要注意的是,代码部分仅供参考,主要关注的内容是设计模式的思想和运用,结合到自己的实战中才是最好的单例模式单例模式的定义是:保证一个类只有一个实例,并提供一个访问他

什么是特权帐户和会话管理

特权帐户和会话管理(PASM)是特权访问管理的一部分,它为用户提供通过远程会话对关键帐户和业务敏感型端点(如数据中心、数据库和应用程序)的管理访问权限。事实上,Gartner已将PASM列为PAM的关键支柱之一,与权限提升和委派管理以及安全远程访问并列。过度的特权伴随着过度的风险,员工拥有的管理权限越多,攻击面就越大。

中小企业建设数字化工厂,选择集成还是重构

随着科技的飞速发展和市场竞争的日益激烈,数字化工厂管理系统已成为中小企业未来发展的必经之路。然而,对于许多中小企业来说,建设数字化工厂并非易事。在建设数字化工厂的过程中,企业需要面对许多问题,其中最关键的问题是:选择集成还是重构?首先,我们需要理解数字化工厂的内涵。数字化工厂是在数字化技术的基础上,将生产全过程数字化,

在Windos 10专业版搭建Fyne(Go 跨平台GUI)开发环境

目录在Windos10专业版搭建Fyne(Go跨平台GUI)开发环境一Fyne和MSYS2简介1.1Fyne1.2MSYS2二安装MSYS22.1下载MSYS22.2安装2.3环境变量设置2.4检测安装环境三参考文档在Windos10专业版搭建Fyne(Go跨平台GUI)开发环境一Fyne和MSYS2简介1.1Fyne

解密list的底层奥秘

🎈个人主页:🎈:✨✨✨初阶牛✨✨✨🐻强烈推荐优质专栏:🍔🍟🌯C++的世界(持续更新中)🐻推荐专栏1:🍔🍟🌯C语言初阶🐻推荐专栏2:🍔🍟🌯C语言进阶🔑个人信条:🌵知行合一金句分享:✨即使人生还有无数次失望的可能性,✨✨但我还是想活在理想主义的乌托邦里.✨目录一、list底层框架(1)节点类

使用Python进行供应链分析

供应链是生产和向客户交付货物所涉及的生产和物流网络。供应链分析是指分析供应链的各个组成部分,以了解如何提高供应链的有效性,为客户创造更多价值。所以,如果你想学习如何分析供应链,这篇文章是给你的。文章中,将带你完成使用Python进行供应链分析的任务。使用Python进行供应链分析导入必要的Python库和数据集开始供应

热文推荐