热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

flaskjson传输失败_GO小知识之实例演示json如何转化为map和struct

简单谈一些JSON数据处理的小知识。近期工作中,因为要把数据库数据实时更新到elasticsearch,在实践过程中遇到了一些JSON数据处理的问题。实

83fde7e3fc203fcc99814de952c9d9c2.png

简单谈一些 JSON 数据处理的小知识。近期工作中,因为要把数据库数据实时更新到 elasticsearch,在实践过程中遇到了一些 JSON 数据处理的问题。

实时数据

实时数据获取是通过阿里开源的 canal 组件实现的,并传通过消息队列 kafka 传输给处理程序。我们将接收到的 JSON 数据类似如下的形式。

{"type": "UPDATE","database": "blog","table": "blog","data": [{"blogId": "100001","title": "title","content": "this is a blog","uid": "1000012","state": "1"}]
}

简单说下数据的逻辑,type 表示数据库事件是新增、更新还是删除事件,database 表示对应的数据库名称,table 表示相应的表名称,data 即为数据库中数据。

怎么处理这串 JSON 呢?

json 转化为 map

最先想到的方式就是通过 json.Unmarshal 将 JSON 转化 map[string]interface{}。

示例代码:

func main () {msg := []byte(`{"type": "UPDATE","database": "blog","table": "blog","data": [{"blogId": "100001","title": "title","content": "this is a blog","uid": "1000012","state": "1"}]}`)var event map[string]interface{}if err := json.Unmarshal(msg, &event); err != nil {panic(err)}fmt.Println(event)
}

打印结果如下:

map[data:[map[title:title content:this is a blog uid:1000012 state:1 blogId:100001]] type:UPDATE database:blog table:blog]

到此,就成功解析出了数据。接下来是使用它,但我觉得 map 通常有几个不足。

  • 通过 key 获取数据,可能出现不存在的 key,为了严谨,需要检查 key 是否存在;
  • 相对于结构体的方式,map数据提取不便且不能利用 IDE 补全检查,key 容易写错;

针对这个情况,可以怎么处理呢?如果能把 JSON 转化为struct 就好了。

json 转化为 struct

在 GO 中,json 转化为 struct 也非常方便,只需提前定义好转化的 struct 即可。我们先来定义一下转化的 struct。

type Event struct {Type string `json:"type"`Database string `json:"database"`Table string `json:"table"`Data []map[string]string `json:"data"`
}

说明几点

  • 实际场景中,canal 消息的 data 结构是由表决定的,在 JSON 成功解析前无法提前知道,所以这里定义为 map[string]string;
  • 转化的结构体成员必须是可导出的,所以成员变量名都是大写,而与 JSON 的映射通过 json:"tagName" 的 tagName 完成。

解析代码非常简单,如下:

e := Event{}
if err := json.Unmarshal(msg, &e); err != nil {panic(err)
}fmt.Println(e)

打印结果:

{UPDATE blog blog [map[blogId:100001 title:title content:this is a blog uid:1000012 state:1]]}

接下来,数据的使用就方便了不少,比如事件类型获取,通过 event.Type 即可完成。不过,要泼盆冷水,因为 data 还是 []map[string]string 类型,在使用时,依然存在前面提到的 map 的问题。

能不能把 map 转化为 struct ?

map 转化为 struct

据我所知,map 转化为 struct 的功能,GO 是没有内置的。如果要实现,需要依赖于 GO 的反射机制。

不过,幸运的是,其实已经有人做了这件事,包名称为 mapstructure,使用也非常简单,敲一遍它提供的几个例子就学会了。README 中也说了,该库主要是遇到必须读取一部分 JSON 才能知道剩余数据结构的场景,和我的场景如此契合。

安装命令如下:

$ go get https://github.com/mitchellh/mapstructure

开始使用前,先定义 map 将转化的 struct 结构,即 blog 结构体,如下:

type Blog struct {BlogId string `mapstructure:"blogId"`Title string `mapstructrue:"title"`Content string `mapstructure:"content"`Uid string `mapstructure:"uid"`State string `mapstructure:"state"`
}

因为,接下来要用的是 mapstructure 包,所以 struct tag 标识不再是 json,而是 mapstructure。

示例代码如下:

e := Event{}
if err := json.Unmarshal(msg, &e); err != nil {panic(err)
}if e.Table == "blog" {var blogs []Blogif err := mapstructure.Decode(e.Data, &blogs); err != nil {panic(err)}fmt.Println(blogs)
}

event 的解析和前面的一样,通过 e.Table 判断是是否来自 blog 表的数据,如果是,使用 Blog 结构体解析。接下来通过 mapstructure 的 Decode 完成解析。

打印结果如下:

[{100001 title this is a blog 1000012 1}]

到此,似乎已经完成了所有工作。非也!

弱类型解析

不知道大家有没有发现一个问题,那就是 Blog 结构体中的所有成员都是 string,这应该是 canal 做的事情,所有的值类型都是 string。但实际上 blog 表中的 uid 和 state 字段其实都是 int。

理想的结构体定义应该是下面这样。

type Blog struct {BlogId string `mapstructure:"blogId"`Title string `mapstructrue:"title"`Content string `mapstructure:"content"`Uid int32 `mapstructure:"uid"`State int32 `mapstructure:"state"`
}

但是当把新的 Blog 类型代入之前的代码,会报如下错误。

panic: 2 error(s) decoding:* '[0].state' expected type 'int32', got unconvertible type 'string'
* '[0].uid' expected type 'int32', got unconvertible type 'string'

提示类型解析失败。其实,这种形式的 json 在其他一些弱类型语言中也会出现。

那如何解决这个问题?提两种解决方案

  • 使用时进行转化,比如类型为 int 的数据,使用时可以用 strconv.Atoi 转化。
  • 使用 mapstructure 提供的软类型 map 转化 struct 的功能;

显然,第一种方式太 low,转化的时候还要多一步错误检查。那第二种方式如何呢?

来看示例代码,如下:

var blogs []Blog
if err := mapstructure.WeakDecode(e.Data, &blogs); err != nil {panic(err)
}fmt.Println(blogs)

其实只需要把 mapstructure 的 Decode 替换成 WeakDecode 就行了,字如其意,若解析。如此easy。

到此,才算完成!接下来的数据处理就简单很多了。如果想学习 mapstructure 的使用,敲敲源码中例子应该差不多了。



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
author-avatar
hhxsv5
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有