golang重载MarshalJSON实现自定义序列化

背景:time.NOW()获得的时间格式是RFC3339格式的,需要把他按照yyyy/MM/dd hh:mm:ss的格式进行json序列化并返回给前端

解决方法:

  1. 给目标类型创建一个别名,并对该别名重载MarshalJSON方法,例如:

    			//给time.Time创建别名为jsonTime
    			type jsonTime time.Time
    			
    			//包含time.Time类型字段的结构体,改用jsonTime这个类型
    			type Message struct {
    				CreateAt    jsonTime `json:"createAt"`
    			}
    			
    			//重写jsonTime类型的MarchalJSON方法,以改变rfc3339的时间格式
    			func (this jsonTime) MarshalJSON() ([]byte, error) {
    				var stamp = fmt.Sprintf("\"%s\"", time.Time(this).Format("2006-01-02 15:04:05"))
    				return []byte(stamp), nil
    			}
    

    如此直接对Message对象进行序列化,其中CreateAt字段的格式就会变成自定义格式。

    			var msg = Message{
    				CreateAt: jsonTime(time.Now()),
    			}
    			marshal, _ := json.Marshal(msg)
    			fmt.Println(string(marshal))
    			//输出结果:
    			{"createAt":"2021-02-02 21:29:36"}
    
  2. 直接对目标结构体重载MarshalJSON方法,例如:

    func (d Message) MarshalJSON() ([]byte, error) {
    	type Alias Message
    	return json.Marshal(struct {
    		Alias
    		CreateAt string `json:"createAt"`
    	}{
    		Alias:      Alias(d),
    		CreateAt: d.CreateAt.Format("2006/01/02 15:04:05"),
    	})
    }
    

    这里利用了匿名结构体和json序列化时的同名字段覆盖特点。

  • 注意到,这里是给Message取了一个别名Alias,这么做的目的是避免对Message.MarchalJSON进行递归调用。
  • 之后构造了一个内容为Alias和CreateAt两个字段的匿名结构体,其中CreateAt的标签与Message中的createAt标签一样为json:"createAt".
  • 在return json.Marshal时,会优先取CreateAt: d.CreateAt.Format("2006/01/02 15:04:05"),的结果作为json串中createAt属性的值,至于是如何实现的,阅读源码之后发现涉及到反射机制,往里钻了几层还是没搞懂,有机会再探究吧。

在这里插入图片描述
在这里插入图片描述
在执行完json.Marshal(s)后,得到的marshal如图:
在这里插入图片描述
至于s.Alias.CreateAt和s.CreateAt序列化结果究竟如何被替换,没搞懂。

这么做似乎有点麻烦,但我感觉非常巧妙,类似地,还可以实现一个结构体对象序列化时添加一些额外的字段,例如:

type Book struct {
  Title        string
  Author       string
}

type FakeBook Book
 
func (b Book) MarshalJSON() ([]byte,error) {
    return json.Marshal(struct {
        FakeBook
        Genre string
    }{
        FakeBook: FakeBook(b),Genre:    "Satire",})
}

//对Book对象的序列化结果:
{
  "Title": "Catch-22","Author": "Joseph Heller","Genre": "Satire"	//可以发现确实多了一个Genre字段
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值