「容器管理系统」开发篇: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 标签,就可以识别到。

相关推荐
KYGALYX4 分钟前
服务异步通信
开发语言·后端·微服务·ruby
掘了9 分钟前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法1 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment1 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte2 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行3 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple3 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东3 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble3 小时前
springboot的核心实现机制原理
java·spring boot·后端
全栈老石4 小时前
Python 异步生存手册:给被 JS async/await 宠坏的全栈工程师
后端·python