基本的序列化与反序列化
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
func main() {
u := User{
Username: "bing",
Password: "12345",
}
//序列化
marshalUser, err := json.Marshal(u)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(string(marshalUser))
//反序列化
unmarshalUser := User{}
err = json.Unmarshal(marshalUser, &unmarshalUser)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("%#v\n", unmarshalUser)
}
运行结果:
{"username":"bing","password":"12345"}
main.User{Username:"bing", Password:"12345"}
如何序列化结构体的部分字段
我们需要json序列化User结构体,但是不想把密码也序列化,又不想修改User结构体,这个时候我们就可以使用创建另外一个结构体PublicUser匿名嵌套原User,同时指定Password 字段为匿名结构体指针类型,并添加omitempty选项,示例代码如下:
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
type PublicUser struct {
*User
Password *struct{} `json:"password,omitempty"`
}
func main() {
u := User{
Username: "bing",
Password: "12345",
}
//序列化
marshalUser, err := json.Marshal(PublicUser{User: &u})
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(string(marshalUser))
}
运行结果如下:
{"username":"bing"}
string选项的用法
有时候,前端在传递来如下的json数据:
{
"username": "bing",
"age": "18",
}
像年龄,分数等字段本应该是整形或浮点型,但是传递过来的全部都是字符串类型,这个时候可以在结构体tag中添加string选项。string选项仅适用于字符串、浮点、整数及布尔类型,意思是可以将这些类型的数据序列化为JSON类型的时候全部转换为string类型,或者将string类型的JSON数据反序列化为这些类型。不过,请勿滥用,尤其是对已经是string类型的数据使用。
具体代码如下:
type User struct {
Username string `json:"username"`
Age int `json:"age,string"`//如果不加string选项,json中的"age":"18"里面的"18"会被反序列化为0
}
func main() {
marshalUser := `{"username":"bing","age":"18"}`
unmarshalUser := User{}
//反序列化
err := json.Unmarshal([]byte(marshalUser), &unmarshalUser)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("%#v\n", unmarshalUser)
}
运行结果如下:
main.User{Username:"bing", Age:18}
自定义MarshalJSON和UnmarshalJSON方法来完成时间字段的解析
Go语言内置的 json 包使用 RFC3339 标准中定义的时间格式,对我们序列化时间字段的时候有很多限制。
type Time struct {
CreateTime time.Time `json:"createTime"`
}
func main() {
marshalTime := `"createTime": "2023-04-10 00:00:01"`
var unmarshalTime Time
err := json.Unmarshal([]byte(marshalTime), &unmarshalTime)
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("%#v\n", unmarshalTime)
}
运行结果如下:
invalid character ':' after top-level value
main.Time{CreateTime:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)}
也就是内置的json包不认识我们常用的字符串时间格式,如 2023-04-10 00:00:01 。常规的解决办法就是自定义MarshalJSON和UnmarshalJSON方法来完成时间字段的解析,像这样的代码网上有很多,比如:时间类型字段的 JSON 序列化和反序列化,但是我认为这种方法并不是很实用。其实如果真的遇到前端传递过来的非标准的时间字段(像"2023-04-10 00:00:01"),办法就是定义两个结构体,第一个结构体的时间类型为string,第二个结构体的时间类型为Time。先把json对象转换为第一个结构体的实例,然后取出string类型的时间,将string类型的时间使用time.Parse()方法转换为Time类型的时间,最后赋值即可。代码如下:
const LAYOUT = "2006-01-02 15:04:05"
type ModelJson struct {
Name string `json:"name"`
Age int `json:"age"`
CreateTime string `json:"createTime"`
}
type Model struct {
Name string `json:"name"`
Age int `json:"age"`
CreateTime time.Time `json:"createTime"`
}
func main() {
//序列化
model := Model{
Name: "bing",
Age: 20,
CreateTime: time.Now(),
}
marshalJson, err := json.Marshal(model)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("序列化")
fmt.Println(string(marshalJson))
fmt.Println()
//反序列化(m为前端传递过来的json数据)
fmt.Println("反序列化")
m := `{"name": "bing","age": 18,"createTime": "2023-04-10 08:30:01"}`
modelJson := ModelJson{}
err = json.Unmarshal([]byte(m), &modelJson)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println("string类型的时间: ")
fmt.Printf("%+v\n", modelJson)
createTime, err := time.Parse(LAYOUT, modelJson.CreateTime)
if err != nil {
fmt.Println(err.Error())
}
modelStruct := Model{
Name: modelJson.Name,
Age: modelJson.Age,
CreateTime: createTime,
}
fmt.Println("将string类型的时间转换为Time类型后: ")
fmt.Printf("%+v\n", modelStruct)
}
运行结果如下: