# formcodec **Repository Path**: aesoper/formcodec ## Basic Information - **Project Name**: formcodec - **Description**: FormCodec 是一个功能强大的 Go 语言表单数据编解码库,支持结构体标签、自定义钩子、嵌套结构、Map 和切片等复杂数据类型的编码与解码。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-25 - **Last Updated**: 2026-03-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # FormCodec [![Go Version](https://img.shields.io/badge/go-1.24+-blue.svg)](https://golang.org) [![License](https://img.shields.io/badge/license-Apache%202.0-green.svg)](LICENSE) FormCodec 是一个功能强大的 Go 语言表单数据编解码库,支持结构体标签、自定义钩子、嵌套结构、Map 和切片等复杂数据类型的编码与解码。 ## 功能特性 - **编码 (Encode)**: 将 Go 结构体编码为 `map[string][]string` (URL 表单格式) - **解码 (Decode)**: 将 `map[string][]string` 解码为 Go 结构体 - **结构体标签**: 支持 `form` 标签自定义字段映射 - **嵌套结构**: 支持嵌套结构体和嵌入结构体 - **复杂类型**: 支持 Map、切片、指针、数组 - **自定义钩子**: 通过编解码钩子扩展支持任意类型 - **内置钩子**: 提供丰富的内置钩子(时间、IP、TextMarshaler 等) ## 安装 ```bash go get gitee.com/aesoper/formcodec ``` ## 快速开始 ### 解码示例 ```go package main import ( "fmt" "gitee.com/aesoper/formcodec" ) type User struct { Name string `form:"name"` Age int `form:"age"` Email string `form:"email"` } func main() { // 模拟表单数据 data := map[string][]string{ "name": {"张三"}, "age": {"25"}, "email": {"zhangsan@example.com"}, } var user User decoder := formcodec.NewDecoder() if err := decoder.Decode(&user, data); err != nil { panic(err) } fmt.Printf("%+v\n", user) // 输出: {Name:张三 Age:25 Email:zhangsan@example.com} } ``` ### 编码示例 ```go package main import ( "fmt" "gitee.com/aesoper/formcodec" ) type User struct { Name string `form:"name"` Age int `form:"age"` Email string `form:"email"` } func main() { user := User{ Name: "张三", Age: 25, Email: "zhangsan@example.com", } dst := make(map[string][]string) encoder := formcodec.NewEncoder() if err := encoder.Encode(user, dst); err != nil { panic(err) } fmt.Printf("%+v\n", dst) // 输出: map[email:[zhangsan@example.com] name:[张三] age:[25]] } ``` ## 高级用法 ### 嵌套结构体 ```go type Address struct { City string `form:"city"` ZipCode string `form:"zip_code"` } type User struct { Name string `form:"name"` Address Address `form:"address"` } // 解码时表单数据格式: // data := map[string][]string{ // "name": {"张三"}, // "address.city": {"北京"}, // "address.zip_code": {"100000"}, // } ``` ### 切片类型 ```go type Config struct { Tags []string `form:"tags"` Scores []int `form:"scores"` } // 解码时表单数据格式: // data := map[string][]string{ // "tags": {"go", "programming", "backend"}, // "scores": {"90", "85", "95"}, // } ``` ### Map 类型 ```go type Config struct { Metadata map[string]string `form:"metadata"` } // 支持两种格式: // 括号格式: metadata[key1]=value1&metadata[key2]=value2 // 点号格式: metadata.key1=value1&metadata.key2=value2 ``` ### 默认值支持 ```go type Config struct { Name string `form:"name" default:"anonymous"` Age int `form:"age" default:"18"` Active bool `form:"active" default:"true"` } // 当源数据中不存在对应字段时,使用 default 标签指定的默认值 data := map[string][]string{} var cfg Config decoder := formcodec.NewDecoder() if err := decoder.Decode(&cfg, data); err != nil { panic(err) } fmt.Printf("%+v\n", cfg) // 输出: {Name:anonymous Age:18 Active:true} ``` ### 使用自定义钩子 ```go import ( "time" "gitee.com/aesoper/formcodec" ) type Event struct { Name string `form:"name"` CreatedAt time.Time `form:"created_at"` Timeout time.Duration `form:"timeout"` } // 解码 - 内置钩子自动处理时间和持续时间 data := map[string][]string{ "name": {"会议"}, "created_at": {"2024-01-15T10:30:00Z"}, "timeout": {"5m30s"}, } var event Event decoder := formcodec.NewDecoder() if err := decoder.Decode(&event, data); err != nil { panic(err) } ``` ### 自定义编解码钩子 ```go // 解码钩子示例: 自定义类型转换 customHook := formcodec.DecodeHookFuncType( func(to reflect.Type, toField reflect.StructField, data string) (any, error) { if to == reflect.TypeOf(MyCustomType{}) { return ParseMyCustomType(data) } return data, nil }, ) decoder := formcodec.NewDecoder(formcodec.WithDecodeHook( formcodec.ComposeDecodeHookFunc(customHook, formcodec.DefaultDecodeHook()), )) ``` ## 支持的类型 ### 基础类型 - `string`, `bool` - `int`, `int8`, `int16`, `int32`, `int64` - `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `uintptr` - `float32`, `float64` - `complex64`, `complex128` - `[]byte`, `rune` ### 复杂类型 - 切片 (`[]T`) - 数组 (`[N]T`) - Map (`map[string]T`) - 指针 (`*T`) - 嵌套结构体 - 嵌入结构体 - 接口 (`any`/`interface{}`) ### 内置钩子支持类型 - `time.Time` - 支持自定义时间格式 (`time_format` 标签) - `time.Duration` - `net.IP` - `net.IPNet` - `url.URL` - `big.Int`, `big.Float`, `big.Rat` - 实现 `encoding.TextMarshaler` 的类型 - 实现 `encoding.TextUnmarshaler` 的类型 - 实现 `fmt.Stringer` 的类型 ## 结构体标签 ### `form` 标签 ```go type Example struct { // 基本用法: 指定字段名 Field1 string `form:"field_1"` // 忽略字段 Field2 string `form:"-"` // omitempty: 编码时忽略空值 Field3 string `form:"field_3,omitempty"` // 时间格式: 指定时间解析/格式化布局 TimeField time.Time `form:"time_field" time_format:"2006-01-02"` } ``` ### `default` 标签 用于指定字段的默认值,当解码时源数据中不存在该字段,将使用默认值填充。 ```go type Config struct { // 字符串默认值 Name string `form:"name" default:"anonymous"` // 数值默认值 Port int `form:"port" default:"8080"` // 布尔默认值 Debug bool `form:"debug" default:"false"` // 浮点数默认值 Timeout float64 `form:"timeout" default:"30.0"` } ``` **注意**: - `default` 标签仅对基础类型有效(string、int、bool、float 等) - 如果源数据中提供了值,将覆盖默认值 - 默认值与 `zeroFields` 选项互斥,设置了 `default` 的字段会优先使用默认值 ## 配置选项 ### 解码器选项 ```go // 自定义标签名 (默认: "form") decoder := formcodec.NewDecoder(formcodec.WithTagName("json")) // 设置自定义解码钩子 decoder := formcodec.NewDecoder(formcodec.WithDecodeHook(myHook)) // 零值字段: 将无对应值的字段设为零值 decoder := formcodec.NewDecoder(formcodec.WithZeroFields(true)) // 忽略未知键: 忽略源数据中无对应结构体字段的键 decoder := formcodec.NewDecoder(formcodec.WithIgnoreUnknownKeys(true)) ``` ### 编码器选项 ```go // 自定义标签名 (默认: "form") encoder := formcodec.NewEncoder(formcodec.WithEncoderTagName("json")) // 设置自定义编码钩子 encoder := formcodec.NewEncoder(formcodec.WithEncodeHook(myHook)) // omitEmpty: 是否忽略空值 (默认: true) encoder := formcodec.NewEncoder(formcodec.WithOmitEmpty(false)) ``` ## 开发 ### 项目结构 ``` . ├── decoder.go # 解码器实现 ├── decoder_test.go # 解码器测试 ├── encoder.go # 编码器实现 ├── encoder_test.go # 编码器测试 ├── decode_hooks.go # 解码钩子定义和内置钩子 ├── encode_hooks.go # 编码钩子定义和内置钩子 ├── go.mod # Go 模块定义 └── Makefile # 开发任务 ``` ### 常用命令 ```bash # 运行测试 make test # 运行测试并生成覆盖率报告 make test-coverage # 运行基准测试 make bench # 代码格式化 make fmt # 代码检查 make lint # 运行所有 CI 检查 make ci ``` ## 许可证 本项目采用 [Apache License 2.0](LICENSE) 许可证。 ## 贡献 欢迎提交 Issue 和 Pull Request!