golang自定义MarshalJSON、UnmarshalJSON 原理和技巧

问题出现的原因:在前后端分离的项目中,经常出现的问题是时间戳格式的问题。
后端的日期格式兼容性强,比较完善。前端由于各种原因,日期格式不完善。
就会产生矛盾。

ms int64比较通用,但是unix时间没有可读性,不方便db运维的工作。

以golang为例,讲一下时间戳转换,在内存里面转换时间戳。

golang的时间戳类型叫做:time.Time,标准是RFC 3339。

RFC 3339 是一种日期 - 时间格式的互联网标准,它基于 ISO 8601 格式。其基本格式为YYYY - MM - DDTHH:MM:SS±HH:MM,其中:

  • YYYY表示四位年份,例如2024。
  • MM表示两位月份,范围是01 - 12。
  • DD表示两位日期,范围是01 - 31。
  • T是日期和时间部分的分隔符,它是一个固定的字符,用于区分日期和时间。
  • HH表示两位小时数,采用 24 小时制,范围是00 - 23。
  • MM表示两位分钟数,范围是00 - 59。
  • SS表示两位秒数,范围是00 - 59。
  • ±HH:MM表示时区偏移量,其中+或-表示相对于 UTC(协调世界时)的偏移方向,HH和MM分别表示小时和分钟的偏移量。例如,+08:00表示东八区,比 UTC 快 8 小时;-05:00表示西五区,比 UTC 慢 5 小时。

例如:

  • 2024-06-15T14:30:00+00:00:表示 2024 年 6 月 15 日,下午 2 点 30 分(14:30),时区为 UTC(偏移量为+00:00)。
  • 2024-12-31T23:59:59-05:00:表示 2024 年 12 月 31 日,晚上 11 点 59 分 59 秒(23:59:59),时区为西五区(偏移量为-05:00)。

为方便展示,我绘制了下面的草图,一个https请求从客户端到达数据库,需要经历的最短路径。 nginx作为入口时,但是数据没有格式化,不适合作为拦截点。 往右边继续看,很明显的发现数据流只有在json 序列化/反序列化的时候开始汇聚。 那RFC 3339 标准的time.Time转换为毫秒在这里实现,无疑是工作量最小的修改方式。
(就像小时候,灌酿造的酱油时,在瓶口处放置一个滤网,过滤掉杂质。 也好像查干湖捕鱼时,工人站在冰面出口处将一个一个的鱼勾起来。 又好像,蜀黍办案,在高速路口排兵布阵,是一样的道理。 在数据处理,找到数据的入口 或 出口,然后轻松拿捏。)

(golang语法或代码没有什么好讲的,总可以借鉴或自定义,属于闻道有先后性质的,没有高低之分。 但是一种思维方式,值得推而广之,用在工作和生活的方方面面,减少你前行的阻力。)

在这里插入图片描述

自定义MarshalJSON, UnmarshalJSON。当应用调用json.Marshal(), json.UnMarshal()时就会调用自定义解析函数。

type DevData struct {QrCodeStr   string  `json:"qrCodeStr"`StartTime      time.Time `json:"StartTime,omitempty" swaggerignore:"false"`StartTimeStamp int64     `json:"startTimeStamp"`
}func (c *DevData) MarshalJSON() ([]byte, error) { type Alias DevDataaux := &Alias{}*aux = Alias(*c)aux.StartTime = time.Unix(aux.StartTimeStamp, 0)aux.EndTime = time.Unix(aux.EndTimeStamp, 0)if data, err := json.Marshal(aux); err == nil { return data, nil                } else {return nil, err}
}func (c *DevData) UnmarshalJSON(data []byte) error {type Alias DevDataaux := &Alias{}if err := json.Unmarshal(data, aux); err != nil {return err}aux.StartTime = time.Unix(aux.StartTimeStamp, 0)aux.EndTime = time.Unix(aux.EndTimeStamp, 0)*c = DevData(*aux)return nil
}

在哪里产生关联:
当一个类型实现了encoding/json包中的json.Marshaler接口的MarshalJSON方法时,json.Marshal函数就会调用这个自定义的MarshalJSON方法来进行 JSON 序列化。json.Marshaler接口定义如下:

type Marshaler interface {MarshalJSON() ([]byte, error)
}type Unmarshaler interface {UnmarshalJSON([]byte) error
} 

在这里插入图片描述
在这里插入图片描述

其中的type Alias DevData,是为了避免套娃无线递归问题。
但是引入了新的问题: 对象多拷贝一次,当数据量比较大,api调用比较频繁的时候,浪费cpu时间。

可以用解析之后,用map遍历,我最开始写golang代码时就用过这个笨方法。

好的解决办法是:限定拷贝的数据范围,将需要特殊处理的时间戳,单独封装在一个结构体里面。这样只有特殊字段会多拷贝一次,其他字段不会出现拷贝。

type TimeInfo struct {StartTime      time.Time `json:"StartTime,omitempty"`    // 设置标签:omitempty,客户端传入空值时,忽略该字段解析不会报错StartTimeStamp int64     `json:"startTimeStamp,omitempty" bson:"-,omitempty"` // 应用传入空值时,解析不报错。 bson注解表示,StartTimeStamp 是一个内存临时变量,不会写入mongodb数据库。
}func (c *TimeInfo) MarshalJSON() ([]byte, error) { type Alias TimeInfoaux := &Alias{}*aux = Alias(*c)aux.StartTime = time.Unix(aux.StartTimeStamp, 0)aux.EndTime = time.Unix(aux.EndTimeStamp, 0)if data, err := json.Marshal(aux); err == nil { return data, nil                } else {return nil, err}
}func (c *TimeInfo) UnmarshalJSON(data []byte) error {type Alias TimeInfoaux := &Alias{}if err := json.Unmarshal(data, aux); err != nil {return err}aux.StartTime = time.Unix(aux.StartTimeStamp, 0)aux.EndTime = time.Unix(aux.EndTimeStamp, 0)*c = TimeInfo(*aux)return nil
}type DevData struct {QrCodeStr   string  `json:"qrCodeStr"`TimeInfo
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/64783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初始Python篇(7)—— 正则表达式

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: Python 目录 正则表达式的概念 正则表达式的组成 元字符 限定符 其他字符 正则表达式的使用 正则表达式的常见操作方法 match方法的…

使用 AI 辅助开发一个开源 IP 信息查询工具:一

本文将分享如何借助当下流行的 AI 工具,一步步完成一个开源项目的开发。 写在前面 在写代码时,总是会遇到一些有趣的机缘巧合。前几天,我在翻看自己之前的开源项目时,又看到了 DDNS 相关的讨论。虽然在 2021 年我写过两篇相对详细的教程&am…

Powershell学习笔记

声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…

《Java源力物语》-2.异常训练场

~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” \quad 在java.lang古域的一处偏僻角落,矗立着一座古老的训练场。青灰色的围墙上布满了密密麻麻的源力符文,这些符文闪烁着…

一起学Git【第二节:创建版本库】

创建库 这个库相当于一个目录,目录中的文件都被Git管理,会记录每个文件的修改删除和添加工作,便于之后随时跟踪历史记录还原到之前的某一版本。如何创建库呢?有两种方式,本地创建库和云端克隆一个库。 1.本地创建库 …

HarmonyOS NEXT 技术实践-基于基础视觉服务的多目标识别

在智能手机、平板和其他智能设备日益智能化的今天,视觉识别技术成为提升用户体验和智能交互的重要手段。HarmonyOS NEXT通过基础视觉服务(HMS Core Vision)提供了一套强大的视觉识别功能,其中多目标识别作为其关键技术之一&#x…

nginx-静态资源部署

目录 静态资源概述 静态资源配置指令 listen指令 server_name指令 精确匹配 ​编辑 ​编辑 使用通配符匹配 使用正则表达式匹配 匹配执行顺序 default_server属性 location指令 root指令 alias指令 root与alisa指令的区别 index指令 error_page指令 直接使用 …

时空信息平台架构搭建:基于netty封装TCP通讯模块(IdleStateHandler网络连接监测,处理假死)

文章目录 引言I 异步TCP连接操作II 心跳机制:空闲检测(读空闲和写空闲)基于Netty的IdleStateHandler类实现心跳机制(网络连接监测)常规的处理假死健壮性的处理假死方案获取心跳指令引言 基于netty实现TCP客户端:封装断线重连、连接保持 https://blog.csdn.net/z92911896…

Linux之RPM和YUM命令

一、RPM命令 1、介绍 RPM(RedHat Package Manager).,RedHat软件包管理工具,类似windows里面的setup,exe是Liux这系列操作系统里而的打包安装工具。 RPMI包的名称格式: Apache-1.3.23-11.i386.rpm “apache’” 软件名称“1.3.23-11” 软件的版本号&am…

aosp15 - Activity生命周期切换

本文探查的是,从App冷启动后到MainActivity生命周期切换的系统实现。 调试步骤 在com.android.server.wm.RootWindowContainer#attachApplication 方法下断点,为了attach目标进程在com.android.server.wm.ActivityTaskSupervisor#realStartActivityLock…

【漫话机器学习系列】017.大O算法(Big-O Notation)

大 O 表示法(Big-O Notation) 大 O 表示法是一种用于描述算法复杂性的数学符号,主要用于衡量算法的效率,特别是随着输入规模增大时算法的运行时间或占用空间的增长趋势。 基本概念 时间复杂度 描述算法所需的运行时间如何随输入数…

ensp 基于端口安全的财务部网络组建

ARP IP数据包通过以太网发送,但以太网设备并不能识别IP地址,它们是以MAC地址传输的。因此,必须把IP目的地址转换成MAC目的地址。在以太网中,一个主机要和另一个主机进行直接通信,必须要知道目标主机的MAC地址。 ARP&…

在 Ubuntu 上安装 Muduo 网络库的详细指南

在 Ubuntu 上安装 Muduo 网络库的详细指南 首先一份好的安装教程是非常重要的 C muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装-CSDN博客 像这篇文章就和shit一样,安装到2%一定会卡住,如果你不幸用了这个那真是遭老罪了 环境&#xf…

Idean 处理一个项目引用另外一个项目jar 但jar版本低的问题

当在idea中一个module A引用另外一个项目B的jar,但是从私服仓库中拉下的jar版本比较低导致编译不通过时,可以把项目B拉下来,重新编译打包jar跟新到本地的仓库 选中右边菜单的Maven 选中对应的项目B-》Lifecycle->双击 install也可以按住c…

Windows下安装Rabbit MQ

一、安装环境: 系统:windows11; 环境配置安装:otp_win64_25.3.2.14.exe(erlang类库); 服务应用安装:rabbitmq-server-3.12.4.exe; 二、erlang环境: 1.执行…

生态学研究中,森林生态系统的结构、功能与稳定性是核心研究

在生态学研究中,森林生态系统的结构、功能与稳定性是核心研究内容之一。这些方面不仅关系到森林动态变化和物种多样性,还直接影响森林提供的生态服务功能及其应对环境变化的能力。森林生态系统的结构主要包括物种组成、树种多样性、树木的空间分布与密度…

基于UNITY3D的照片墙演示项目技术分享

unity实现超大图片墙演示,由于拥有海量图片,使用了CPU 多线程,unity dots技术,图片组成文字部分,使用了点阵图技术,提取文字像素。 (关于点阵介绍) 点阵字体是把每一个字符都分成1616或2424个点…

设计模式-访问者设计模式

介绍 访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变个元素的类的前提下定义作用于这些元素的新操作。 问题:在一个机构里面有两种员工,1.Teacher 2.Engineer 员…

ISO/IEC 25010:2023 系统和软件的质量模型(产品质量模型)

本文是对ISO/IEC 25010 2023年底第2版:系统和软件工程-系统和软件质量要求与评估 (SQuaRE)-产品质量模型一文的转载,此外还参考了ISO/IEC 25019:2023(en) Systems and software engineering — Systems and software Quality Requirements and Evaluatio…

【零基础保姆级教程】制作自己的数据集——Labelimg的安装与使用及常见的报错解决方法

1.是什么 LabelImg 是一个图形化的图像标注工具,主要用于机器学习和计算机视觉领域中的数据预处理。它是由 GitHub 用户 tzutalin 开发的开源项目,基于 Python 和 Qt 框架编写。LabelImg 允许用户手动为图像添加边界框(bounding boxes&#…