关于Go语言的json技巧

本文介绍了Go语言中如何进行基本的序列化与反序列化操作,以及如何处理结构体的部分字段,特别是不序列化敏感信息如密码。还讨论了`string`选项的使用,允许将数字字段作为字符串处理。此外,文章讨论了自定义`MarshalJSON`和`UnmarshalJSON`方法来处理非标准时间格式的问题,提出了解决方案,即通过转换结构体和解析字符串时间来适应不同的时间格式需求。
摘要由CSDN通过智能技术生成

基本的序列化与反序列化

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)
}

运行结果如下:
image-20230412202647052

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值