「容器管理系统」开发篇:4. Gin 如何优雅的使用 struct 的 tag 标签

回顾

项目已开源:基于 Golang 的 容器管理系统

Gin 请求参数绑定解读

在使用 Gin Web 框架时,接收参数一般是这样操作:

  1. 定义接收参数的 struct 结构体
go 复制代码
type ParamsRequest struct{
    UserName string `json:"user_name" form:"user_name"`
    ...
}
  1. 使用 ShouldBind 系列函数,对接收的 struct 结构体进行赋值,会识别 struct 中的 tag 标签

ShouldBind 系列函数包含:

ShouldBind、ShouldBindJSON、ShouldBindXML、ShouldBindQuery、ShouldBindYAML、ShouldBindTOML、ShouldBindHeader、ShouldBindUri、ShouldBindWith、ShouldBindBodyWith

10 个函数,用来获取各种格式的请求。使用方式可以参考 Gin 源码 context.go 这个文件。

这里咱们就主要讲解前两个函数: ShouldBindShouldBindJSON

注意: ShouldBind 系列函数 会默认识别 form tag 标签,如果没有设置 form tag 标签,会退而求其次,识别 json tag 标签,如果根本就没有设置 tag, 会使用 struct 的属性名
所以:在请求传参时,需要根据 structtag 标签的名字进行传参才会识别到数据,进行赋值

  • ShouldBind 是一个通用获取,可以根据请求类型和请求的内容类型 Content-Type 来自动识别是什么格式的请求,走对应的格式进行赋值,一般不指定请求格式的就使用这个
go 复制代码
var params ParamsRequest
if err := c.ShouldBind(&params); err != nil {
    return
}
  • ShouldBindJSON 是用来专门获取 json 请求的,前置条件是: struct 中 设置对应的 json tag 标签
go 复制代码
var params ParamsRequest
if err := c.ShouldBindJSON(&params); err != nil {
    return
}

项目中咱们使用的:ShouldBindJSON, 通过上面的解读,是不是认为 Gin 的参数获取已经做得很好了,可以直接进行赋值拿到了,下面直接用就好了,话是这么说,在这里我提出一个问题: 拿到参数之后,对数据库操作,你会在怎么做呢?

如何操作 structtag

这里有以下方法可以操作:

  • 通过官方 reflect 反射包解析 tag 标签
go 复制代码
func ToTags(c any, tagName string) (fields []string) {
    tagFields := []reflect.StructField{}

    ct := reflect.TypeOf(c)
    for i := 0; i < ct.NumField(); i++ {
       tagFields = append(tagFields, ct.Field(i))
    }

    for _, val := range tagFields {
       tagValue := val.Tag.Get(tagName)
       if tagValue != "" {
          fields = append(fields, strings.Split(tagValue, ",")[0])
       }
    }
    return fields
}

structs.ToTags(any, "json")

上面这段代码可以解析到 tag 标签,并返回出一个 字符数组进行接收,但是你解析出来之后,如何对你定义的数据库 modelstruct 进行赋值呢?

如何将传参的 struct 优雅的赋值到 modelstruct 中?

这里使用到了 encoding/json 官方 JSON

  • 定义一个 model structparams struct
go 复制代码
type ParamsRequest struct {
    IdOne uint32 `json:"id_one"`
    IdTwo string `json:"id_two"`
}

type ModelStruct struct {
    IdOne uint32 `json:"id_one"`
    IdTwo uint32 `json:"id_two"`
}
  • 实现函数:
go 复制代码
func (c *ModelStruct) ParseFields(p any) *ModelStruct {
    if p == nil {
       return c
    }
    pjson, err := json.Marshal(p)
    if err != nil {
       return c
    }

    err = json.Unmarshal(pjson, c)
    if err != nil {
       return c
    }
    return c
}

解析步骤:

  • 第一步: 使用 json.Marshalparams struct 转换为 params []byte
  • 第二步: 使用 json.Unmarshalparams []byte 转换为 model struct
  • 第三步: 重新返回 model struct (这一步是返回新的 model struct 避免重复赋值)

结束语

  • 使用了 encoding/json 包的特性:json.Marshal、json.Unmarshal
  • json.Marshal 可以将指定的 struct 序列化成 json 格式的数据
  • json.Unmarshal 可以将任意 json 格式的数据转换到指定的 struct

这里的 struct 不规定是同一个,可以使用不同的 struct 进行相互转换,只要对应的 struct 有对应的属性和 tag 标签,就可以识别到。

相关推荐
想打游戏的程序猿8 小时前
核心概念层——深入理解 Agent 是什么
后端·ai编程
woniu_maggie9 小时前
SAP Web Service日志监控:如何用SRT_UTIL快速定位接口问题
后端
一线大码9 小时前
Java 使用国密算法实现数据加密传输
java·spring boot·后端
Rust语言中文社区9 小时前
【Rust日报】用 Rust 重写的 Turso 是一个更好的 SQLite 吗?
开发语言·数据库·后端·rust·sqlite
在屏幕前出油10 小时前
06. FastAPI——中间件
后端·python·中间件·pycharm·fastapi
wuqingshun31415911 小时前
说一下spring的bean的作用域
java·后端·spring
不会写DN11 小时前
GORM 实战入门:从环境搭建到企业级常用特性全解析
sql·mysql·go·gin
钟智强12 小时前
从2.7GB到481MB:我的Docker Compose优化实战,以及为什么不能全信AI
后端·docker
华科易迅12 小时前
Spring JDBC
java·后端·spring
小村儿13 小时前
一起吃透 Claude Code,告别 AI 编程迷茫
前端·后端·ai编程