diff --git a/README.cn.md b/README.cn.md index ee1b56f..cd9e2f8 100644 --- a/README.cn.md +++ b/README.cn.md @@ -36,6 +36,13 @@ func main() { ## 功能列表 +### jsonUtil Json处理工具 + +```go +// JsonToStruct 将 JSON 字符串解析为指定的结构体指针 +func JsonToStruct(jsonData string, result interface{}) error +``` + ### ValidUtil 验证工具 ```go diff --git a/jsonUtil/README.md b/jsonUtil/README.md index ddce627..616fc1b 100644 --- a/jsonUtil/README.md +++ b/jsonUtil/README.md @@ -1 +1,6 @@ -### jsonUtil Json处理工具 \ No newline at end of file +### jsonUtil Json处理工具 + +```go +// JsonToStruct 将 JSON 字符串解析为指定的结构体指针 +func JsonToStruct(jsonData string, result interface{}) error +``` \ No newline at end of file diff --git a/jsonUtil/json_to_struct.go b/jsonUtil/json_to_struct.go new file mode 100644 index 0000000..0f7fdbf --- /dev/null +++ b/jsonUtil/json_to_struct.go @@ -0,0 +1,111 @@ +// Package jsonUtil Json数据处理包 +// 可用于json赋值结构体,json数据转义 +package jsonUtil + +import ( + "encoding/json" + "reflect" + "strconv" +) + +// JsonToStruct 将 JSON 字符串解析为指定的结构体指针 +// 根据结构体的字段类型和标签来自动选择将 JSON 值转换为相应的类型。 +// +// 支持的字段类型包括 string、int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64、bool、float32 和 float64。 +// +// 支持的标签有 "json"、"jsonb" 和 "mapstructure"。 +// - "json" 和 "jsonb" 标签指示解析 JSON 时使用的键名。 +// - "mapstructure" 标签指示字段名的映射关系。 +// +// 如果 JSON 中的某些键在结构体中没有对应的字段,则它们将被忽略。 +// 如果 JSON 中的某些键的类型与结构体中的字段类型不匹配,则会引发解析错误。 +// +// 参数 jsonData 是要解析的 JSON 字符串。 +// 参数 result 是指向要填充 JSON 值的结构体指针。 +// +// 如果解析成功,则返回 nil。如果解析失败,则返回解析错误。 +func JsonToStruct(jsonData string, result interface{}) error { + var data map[string]interface{} + err := json.Unmarshal([]byte(jsonData), &data) + if err != nil { + return err + } + + resultValue := reflect.ValueOf(result).Elem() + resultType := resultValue.Type() + + for i := 0; i < resultType.NumField(); i++ { + fieldType := resultType.Field(i) + fieldName := fieldType.Name + fieldValue := resultValue.FieldByName(fieldName) + + jsonTag := fieldType.Tag.Get("json") + if jsonTag == "" { + jsonTag = fieldName + } + + value, ok := data[jsonTag] + if !ok { + continue + } + + switch fieldValue.Kind() { + case reflect.String: + fieldValue.SetString(value.(string)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch value.(type) { + case float64: + fieldValue.SetInt(int64(value.(float64))) + case string: + if intValue, err := strconv.ParseInt(value.(string), 10, 64); err == nil { + fieldValue.SetInt(intValue) + } + default: + fieldValue.SetInt(int64(value.(int))) + } + case reflect.Float32, reflect.Float64: + switch value.(type) { + case float64: + fieldValue.SetFloat(value.(float64)) + case string: + if floatValue, err := strconv.ParseFloat(value.(string), 64); err == nil { + fieldValue.SetFloat(floatValue) + } + } + case reflect.Struct: + if subData, ok := value.(map[string]interface{}); ok { + subResult := reflect.New(fieldValue.Type()) + JsonToStruct(convertToJSONString(subData), subResult.Interface()) + fieldValue.Set(subResult.Elem()) + } + case reflect.Slice: + if subData, ok := value.([]interface{}); ok { + subResult := reflect.MakeSlice(fieldValue.Type(), len(subData), len(subData)) + for j := 0; j < len(subData); j++ { + subValue := subData[j] + subElem := subResult.Index(j) + + if subElem.Kind() == reflect.Struct { + if subDataElem, ok := subValue.(map[string]interface{}); ok { + subResultElem := reflect.New(subElem.Type()) + JsonToStruct(convertToJSONString(subDataElem), subResultElem.Interface()) + subElem.Set(subResultElem.Elem()) + } + } else { + subElem.Set(reflect.ValueOf(subValue)) + } + } + fieldValue.Set(subResult) + } + default: + fieldValue.Set(reflect.ValueOf(value)) + } + } + + return nil +} + +func convertToJSONString(data map[string]interface{}) string { + jsonBytes, _ := json.Marshal(data) + return string(jsonBytes) +} diff --git a/jsonUtil/json_to_struct_test.go b/jsonUtil/json_to_struct_test.go new file mode 100644 index 0000000..bb36794 --- /dev/null +++ b/jsonUtil/json_to_struct_test.go @@ -0,0 +1,126 @@ +package jsonUtil + +import ( + "fmt" + "log" + "testing" +) + +func TestJsonToStruct(t *testing.T) { + type Address struct { + City string `json:"city"` + Country string `json:"country"` + } + + type Person struct { + Name string `json:"name"` + Age int `json:"age"` + Address Address `json:"address"` + Emails []string `json:"emails"` + } + + jsonData := `{ + "name": "John Doe", + "age": 30, + "address": { + "city": "Shanghai", + "country": "China" + }, + "emails": [ + "john.doe@example.com", + "jdoe@example.com" + ] + }` + + expectedPerson := Person{ + Name: "John Doe", + Age: 30, + Address: Address{ + City: "Shanghai", + Country: "China", + }, + Emails: []string{"john.doe@example.com", "jdoe@example.com"}, + } + + var resultPerson Person + err := JsonToStruct(jsonData, &resultPerson) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if resultPerson.Name != expectedPerson.Name { + t.Errorf("Name field mismatch: expected %s but got %s", expectedPerson.Name, resultPerson.Name) + } + + if resultPerson.Age != expectedPerson.Age { + t.Errorf("Age field mismatch: expected %d but got %d", expectedPerson.Age, resultPerson.Age) + } + + if resultPerson.Address.City != expectedPerson.Address.City { + t.Errorf("Address.City field mismatch: expected %s but got %s", expectedPerson.Address.City, resultPerson.Address.City) + } + + if resultPerson.Address.Country != expectedPerson.Address.Country { + t.Errorf("Address.Country field mismatch: expected %s but got %s", expectedPerson.Address.Country, resultPerson.Address.Country) + } + + if len(resultPerson.Emails) != len(expectedPerson.Emails) { + t.Errorf("Emails length mismatch: expected %d but got %d", len(expectedPerson.Emails), len(resultPerson.Emails)) + } + + for i, expectedEmail := range expectedPerson.Emails { + if resultPerson.Emails[i] != expectedEmail { + t.Errorf("Emails[%d] mismatch: expected %s but got %s", i, expectedEmail, resultPerson.Emails[i]) + } + } +} + +func TestJsonToStruct2(t *testing.T) { + type Address struct { + City string `json:"city"` + Country string `json:"country"` + } + + type Person struct { + Name string `json:"name"` + Age int `json:"age"` + Address Address `json:"address"` + Interests []string `json:"interests"` + } + + jsonData1 := `{ + "name": "Bob", + "age": 25, + "address": { + "city": "Shanghai", + "country": "China" + }, + "interests": ["reading", "swimming"] + }` + + var person1 Person + err := JsonToStruct(jsonData1, &person1) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("person1:%+v \n", person1) + + jsonData2 := `{ + "name": "Bob", + "age": "25", + "address": { + "city": "Shanghai", + "country": "China" + }, + "interests": ["reading", "swimming"] + }` + + var person2 Person + err = JsonToStruct(jsonData2, &person2) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("person2:%+v,, address:%+v \n", person2, person2.Address) +} diff --git a/jsonUtil/json_util.go b/jsonUtil/json_util.go deleted file mode 100644 index 6beefd6..0000000 --- a/jsonUtil/json_util.go +++ /dev/null @@ -1 +0,0 @@ -package jsonUtil diff --git a/validUtil/account.go b/validUtil/account.go index 10f17a0..920be6d 100644 --- a/validUtil/account.go +++ b/validUtil/account.go @@ -1,3 +1,4 @@ +// Package validUtil 验证社交账号 package validUtil import ( diff --git a/validUtil/bank_card.go b/validUtil/bank_card.go index 6f0c689..c111f46 100644 --- a/validUtil/bank_card.go +++ b/validUtil/bank_card.go @@ -1,3 +1,4 @@ +// Package validUtil 验证银行卡号 package validUtil import ( diff --git a/validUtil/datetime.go b/validUtil/datetime.go index a33e0e0..0185036 100644 --- a/validUtil/datetime.go +++ b/validUtil/datetime.go @@ -1,3 +1,4 @@ +// Package validUtil 验证时间与日期格式 package validUtil import (