gin框架

初识gin

Gin 是一个 Go (Golang) 编写的轻量级 http web 框架,运行速度非常快。点击此处访问官方文档。

基本使用
I. 响应
  • 入门案例
func main() {
	router := gin.Default()
	router.GET("/hello", func(c *gin.Context) {
		c.String(http.StatusOK, "Hello World!")
	})
	_ = router.Run(":8080")
	// _ = http.ListenAndServe(":8080", router)
}
  • 响应json数据
func main() {
	router := gin.Default()
	router.GET("/hello", func(c *gin.Context) {
		type User struct {
			UserName string `json:"user_name"`  // 自定义json字段名称
			Age      int    `json:"age"`
			Password string `json:"-"` // 不去序列化该字段
		}
		user := User{
			UserName: "lc",
			Age:      20,
			Password: "123456",
		}
		c.JSON(http.StatusOK, user)
		// 直接响应json
		//c.JSON(http.StatusOK, gin.H{"user_name": "lc", "age": 23})
	})
	_ = router.Run(":8080")
}
  • 响应xml/yaml数据
func _xml(c *gin.Context) {
	c.XML(http.StatusOK, gin.H{"user_name": "lc", "age": 23, "data": gin.H{"name": "test"}})
}

func _yaml(c *gin.Context) {
	c.YAML(http.StatusOK, gin.H{"user_name": "lc", "age": 23})
}
func main() {
	router := gin.Default()
	//router.GET("/json", _json)
	router.GET("/xml", _xml)
	router.GET("/yaml", _yaml)
	_ = router.Run(":8080")
}
  • 响应html
// 参考:https://gin-gonic.com/zh-cn/docs/examples/html-rendering/
func _html(c *gin.Context) {
	c.HTML(http.StatusOK, "index.html", gin.H{"username": "lc"})
}

func main() {
	router := gin.Default()
	// 加载模板目录
	router.LoadHTMLGlob("template/*")
	router.GET("/html", _html)
	_ = router.Run(":8080")
}
  • 文件响应
func main() {
	router := gin.Default()
	// 加载模板目录
	router.LoadHTMLGlob("template/*")
	// 在go中,可以理解为没有相对文件的路径,只有相对项目的路径
	// 访问单个文件
	router.StaticFile("/titian", "static/titian.png")
	router.StaticFS("/static", http.Dir("static/"))
	_ = router.Run(":8080")
}
  • 重定向
// 301和302区别: 301重定向通常用于永久性的URL改变,例如网站迁移、改变域名等;302重定向通常用于临时性的内容改变和URL重定向,例如网站维护期间,原URL临时跳转到维护通知页面。
router.GET("/baidu", func(c *gin.Context) {
		c.Redirect(301, "https://www.baidu.com")
		// 可以跳转自定义路径
		// c.Redirect(301, "/html")
	})
II. 参数
  • 查询参数
func _query(c *gin.Context) {
	fmt.Println(c.GetQuery("user"))
	fmt.Println(c.Query("user"))
	fmt.Println(c.QueryArray("user")) // 拿到多个相同参数
}
// query?id=2&user=lc&user=l3
  • 动态参数
func _param(c *gin.Context) {
	fmt.Println(c.Param("user_id"))
	fmt.Println(c.Param("book_id"))
}

func main() {
	router := gin.Default()
	router.GET("/param/:user_id", _param)
	router.GET("/param/:user_id/:book_id", _param)

	_ = router.Run(":8080")
}
//  http://localhost:8080/param/12323
  • 表单参数
func _form(c *gin.Context) {
	fmt.Println(c.PostForm("name"))
	fmt.Println(c.PostFormArray("name"))
	fmt.Println(c.DefaultPostForm("addr", "四川")) // 如果用户没传,使用默认值
	fmt.Println(c.DefaultQuery("age", "27"))     // 如果用户没传,使用默认值
	forms, err := c.MultipartForm()  // 接受所有的form参数
	fmt.Println(forms, err)
}

func main() {
	router := gin.Default()
	router.POST("/form", _form)
	_ = router.Run(":8080")
}
  • 请求头的各种获取方式
router.GET("/header", func(c *gin.Context) {
		fmt.Println(c.GetHeader("User-Agent"))
		fmt.Println(c.Request.Header)
		// 使用map方式获取需要区分大小写
		fmt.Println(c.Request.Header["User-Agent"])
		// 设置响应头
		// c.Header("token", "112233")
		c.JSON(200, gin.H{"msg": "success"})
	})
III.绑定参数

gin中的bind可以很方便的将前端传递的数据与结构体进行参数绑定,以及参数校验。在使用这个功能的时候,需要给结构体加上Tag-----json,form,url,xml

  • 具体使用
type UserInfo struct {
	Name string `json:"name" form:"name" uri:"name"`
	Age  int    `json:"age" form:"age" uri:"age"`
	Sex  string `json:"sex" form:"sex" uri:"sex"`
}

func main() {
	router := gin.Default()
	// json
	router.POST("/", func(c *gin.Context) {
		// 如果校验不通过会返回错误
		//c.BindJSON()
		var userInfo UserInfo
		err := c.ShouldBindJSON(&userInfo)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "出错了",
			})
			return
		}
		c.JSON(200, userInfo)
	})

	// query
	router.POST("/query", func(c *gin.Context) {
		var userInfo UserInfo
		err := c.ShouldBindQuery(&userInfo)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "出错了",
			})
			return
		}
		c.JSON(200, userInfo)
	})

	// uri
	router.POST("/uri/:name/:age/:sex", func(c *gin.Context) {
		var userInfo UserInfo
		err := c.ShouldBindUri(&userInfo)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "出错了",
			})
			return
		}
		c.JSON(200, userInfo)
	})

	// form-data参数
	router.POST("/form", func(c *gin.Context) {
		var userInfo UserInfo
		err := c.ShouldBind(&userInfo)
		if err != nil {
			c.JSON(200, gin.H{
				"msg": "出错了",
			})
			return
		}
		c.JSON(200, userInfo)
	})

	_ = router.Run(":8080")
}
  • bind绑定器

常用验证器

required: 必填字段,如: binding:"required"
min 最小长度
max 最大长度
len 长度
eq  等于
ne  不等于
gt  大于
gte 大于等于
lt 小于
lte 小于等于
eqfield 等于其他字符的值
nefield 不等于其他字符的值
- 忽略字段: binding:"-"

gin内置验证器

oneof=man women // 枚举 只能是man women
contains=f   // 包含f的字符串
excludes=f   // 不包含f的字符串
startswith   // 字符串前缀
endswith     // 字符串后缀

dive  // LikeList   []string `json:"like_list" binding:"required,dive,required,startswith=lire"`

ip
uri
url

datetime // 1月2号下午3点4分5秒  在06年   

自定义验证的错误信息

// GetValidMsg 获取结构体中的msg参数
func GetValidMsg(err error, obj any) string {
	getObj := reflect.TypeOf(obj)
	// 将err断言为具体类型
	if errs, ok := err.(validator.ValidationErrors); ok {
		// 断言成功
		for _, e := range errs {
			// 循环每一个错误信息
			// 根据报错的字段名获取结构体具体字段
			if f, exist := getObj.Elem().FieldByName(e.Field()); exist {
				msg := f.Tag.Get("msg")
				return msg
			}
		}
	}
	return err.Error()
}

func main() {
	router := gin.Default()
	router.POST("/", func(c *gin.Context) {
		type User struct {
			Name string `json:"name" binding:"required" msg:"用户名校验失败"`
			Age  int    `json:"age" binding:"required" msg:"请输入年龄"`
		}
		var user User
		err := c.ShouldBindJSON(&user)
		if err != nil {
			c.JSON(200, gin.H{"msg": GetValidMsg(err, &user)})
			return
		}
		c.JSON(200, gin.H{"data": user})
	})
	_ = router.Run(":8080")
}

自定义验证器

type User struct {
	Name string `json:"name" binding:"required,sign" msg:"用户名校验失败"`
	Age  int    `json:"age" binding:"required" msg:"请输入年龄"`
}

func signValid(fl validator.FieldLevel) bool {
	var nameList = []string{"ll", "cc", "33"}
	for _, nameStr := range nameList {
		name := fl.Field().Interface().(string)
		if name == nameStr {
			return false
		}
	}
	return true
}

func main() {
	router := gin.Default()
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		_ = v.RegisterValidation("sign", signValid)
	}
	router.POST("/", func(c *gin.Context) {

		var user User
		err := c.ShouldBindJSON(&user)
		if err != nil {
			c.JSON(200, gin.H{"msg": err.Error()})
			return
		}
		c.JSON(200, gin.H{"data": user})
	})
	_ = router.Run(":8080")
}
IV. 中间件
  • 单个路由中间件
func m1(c *gin.Context) {
	fmt.Println("m1...in")
	c.Next()
	fmt.Println("m1...out")
}

func m2(c *gin.Context) {
	fmt.Println("m2...in")
	c.Next()
	fmt.Println("m2...out")
}
func main() {
	router := gin.Default()
	router.GET("/", m1, func(c *gin.Context) {
		fmt.Println("index...in")
		c.JSON(200, gin.H{"msg": "index"})
		// 拦截后续响应
		//c.Abort()
		c.Next() // 类似于栈
		fmt.Println("index...out")
	}, m2)
	_ = router.Run(":8080")
}
// 输出顺序
//m1...in
//index...in
//m2...in
//m2...out
//index...out
//m1...out
// 如果其中一个中间件响应了abort(),后续中间件将不再执行
  • 全局中间件和中间件传参
func m10(c *gin.Context) {
	fmt.Println("m10...in")
}
func main() {
	router := gin.Default()
	router.Use(m10)
	router.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{"msg": "index"})
	})
	router.GET("/m10", func(c *gin.Context) {
		c.JSON(200, gin.H{"msg": "index"})
	})
	_ = router.Run(":8080")
}

注:本文档参考枫枫知道大佬的gin教程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值