关于json传输的过程中字段不对应的问题

2024-01-01 10:58

本文主要是介绍关于json传输的过程中字段不对应的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://github.com/singgel?tab=repositories 

前情摘要

先来一点故事补充,话说小明的领导给小明安排了一个任务,很简单就是调用别人的API,我们作为Client接收数据并进行相应的处理,领导说由于各种原因,目前不知道对方接口的返回数据格式,所以你先做数据解析吧,先写XML格式的,于是小明开始着手工作了,经过编码,调试,并且领导也review通过了。但是,领导接到消息说数据格式好像是JSON格式的,小明只好重新开始工作了。解析XML格式的代码请点击访问以下链接:

解析XML格式代码

代码编写之JSONObject解决一切

小明一听解析JSON格式,那不是手到擒来么,以前经常这么干,如以下代码所示

JSONObject jsonObject = new JSONObject(assetJson);JSONArray jsonArray = jsonObject.getJSONArray("value");for(int i=0;i<jsonArray.length();i++) {JSONObject jsonObj = jsonArray.getJSONObject(i);if(jsonObj.has("AssetNumber") && !jsonObj.isNull("AssetNumber")) {asset.setAssetNumber(jsonObj.getLong("AssetNumber"));}

这段代码应该都能读懂,就是传进来一个Json字符串,然后用一个实体类接收,为了防止异常保证代码健壮性,很多人都会像小明一样加上jsonObject.has(key)和jsonObject.isNull(key)。这时候小明正在为自己的小聪明得意,但是殊不知,这个json对象中有60多个key,意思就是得为这个小聪明多写120行重复的代码。然后再仔细一看,对方的API返回的数据,字段都是超级多,很显然,这么多重复代码无论你是放在Service层处理还是直接裸在Controller里都不是很友好。然后你是不是以为我要提高代码的可重用性,哈哈,这样的代码如果按这个思路来的话是没有办法简化的。那怎么办,换一个思路咯。(有点小啰嗦,请见谅)

代码编写之Json反序列化

小明想了想,现在整体项目使用的是spring boot,spring boot里集成了restTemplate,客户端根据自己的需要可以重写这里关于restTemplate的就不在赘述了。看到一篇关于HttpMessageConverter的文章,希望在你重写restTemplate的时候能帮助你完成关于消息类型转换的工作。如下:

https://segmentfault.com/a/1190000012659486

长话短说,封装好自己的restTemplate。小明想着使用实体类直接去接收服务端传过来的Json数据,代码如下:

public ResponseEntity<JsonResultForMaterial> getMaterials() {return this.restTemplate.exchange( getNlyteServiceEndpoint()+ GetMaterialsURL, HttpMethod.GET,getDefaultEntity(), JsonResultForMaterial.class);}

json数据例子如下:

{"@odata.context": "/$metadata#Materials","value": [{"@odata.type": "#Nlyte.Model.StandardNetworkMaterial","MaterialID": 1},{"@odata.type": "#Nlyte.Model.StandardServerMaterial","MaterialID": 96},{"@odata.type": "#Nlyte.Model.BladeServerMaterial","MaterialID": 101}],"@odata.nextLink": "Materials?$skip=200"}

 

由于服务端传过来的json数据格式问题,小明写了如下实体类

import java.util.List;import com.fasterxml.jackson.annotation.JsonProperty;public class JsonResultForMaterial {@JsonProperty(value="@odata.context")private String odatacontext;private List<Material> value;@JsonProperty(value="@odata.nextLink")private String odatanextLink;public String getOdatacontext() {return odatacontext;}public void setOdatacontext(String odatacontext) {this.odatacontext = odatacontext;}public String getOdatanextLink() {return odatanextLink;}public void setOdatanextLink(String odatanextLink) {this.odatanextLink = odatanextLink;}public List<Material> getValue() {return value;}public void setValue(List<Material> value) {this.value = value;}}package com.vmware.wormhole.nlyteworker.model;import com.fasterxml.jackson.annotation.JsonProperty;public class Material {@JsonProperty(value = "@odata.type")private String odataType;@JsonProperty(value = "MaterialID")private int materialID;public String getOdataType() {return odataType;}public void setOdataType(String odataType) {this.odataType = odataType;}public int getMaterialID() {return materialID;}public void setMaterialID(int materialID) {this.materialID = materialID;}}
在Json反序列化过程中,key需要和你定义的实体类的属性对应,但是大家都知道,实体类属性的命名规范,关于首字母和特殊字符的问题是很严格的。以上json数据中出现了,这样的key如:
@odata.context 、MaterialID

这样是无法直接用实体类接收的。这时候需要用到@JsonProperty(),来修饰具体属性,这样就可以解决无法映射的问题。

这样我们就获得了一个json结果对象,里面有我们需要操作的属性。这里不用考虑,开篇的那个问题,比如key是否存在,key的值是否为空。然后代码可以改成如下:

public List<Asset> getAssetsFromNlyte(List<NlyteAsset> nlyteAssets) {List<Asset> assetsFromNlyte = new ArrayList<Asset>();Asset asset;for(NlyteAsset nlyteAsset:nlyteAssets) {asset = new Asset();asset.setAssetNumber(nlyteAsset.getAssetNumber());asset.setTag(nlyteAsset.getTag());assetsFromNlyte.add(asset);}return assetsFromNlyte;}

这里其实是和开篇的代码做的事情是一样的,不同的是,开篇的代码接收到的是一个json字符串,需要使用JSONObject和JSONArray等进行处理,还需要判断key等等,最后再进行数据的封装。这里的代码直接接收到一个list,然后直接进行遍历,封装数据。这里就解决了,要写很多has(key)和isNull(key)判断的问题。

 

@JsonProperty,@NotNull,@JsonIgnore的具体实例使用,和其中发现的一些问题。

场景分析一

小明做了一个web表单,用来填写并保存数据,后台写restful接口接收数据并保存。写完之后让老大review的时候,自信满满的小明,又收到了很多comment。小明看到了这些comment发现确实有不足之处,比如表单里的有些数据是必须不为空的,虽然在页面上加上了强校验(Js校验),但是后台接口是对外开放的restful接口,别人不走页面直接访问接口存储数据,这时候页面的校验就显得很尴尬了,小明又想这好办啊,直接拿接收到的参数进行非空判断不就行了么,其实也是可以的,但是小明在研究@JsonProperty的时候发现@NotNull正好解决这个问题。代码展示如下:

Student类

public class Student {@JsonProperty(value="real_name")private String name ;@NotNull(message="idcard is not null")private String idCard;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdCard() {return idCard;}public void setIdCard(String idCard) {this.idCard = idCard;}}

StudentController.java(注:这里为了测试方便未按照标准的restApi书写,如需学习标准的restful接口风格请移步百度。请见谅)

public class Student {@JsonProperty(value="real_name")private String name ;@NotNull(message="idcard is not null")private String idCard;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdCard() {return idCard;}public void setIdCard(String idCard) {this.idCard = idCard;}}

Postman测试如下:(条件是:正常输入real_name和idCard,返回结果正常)

Postman测试结果如下(条件:只写real_name,不填写idCard。报错)

注意接口书写时,用@RequestBody接收输入参数时,这时候也需要匹配你预先定义的@JsonProperty的值。参考real_name.并且,在参数前需要加上@Valid,你定义的@NotNull校验才会生效。

@JsonProperty(value="real_name")
private String name ;

场景分析二

idCard为用户的敏感信息,在接口返回数据中不能展示出来,以免用户敏感信息直接暴露在外。这时候,小明想到了另外一个注解,@JsonIgnore,在Student对象序列化为json数据的返回的时候,忽略该属性。代码及测试如下:

@JsonProperty(value="real_name")private String name ;@JsonIgnoreprivate String idCard;

Postman测试如下(条件:正常输入real_name和idCard,观察返回数据,只包含real_name)

 

场景分析三

在场景二中提到使用@JsonIgnore可以让接口在返回数据的时候不序列化一些属性。但是小明又想了,若场景一和场景二结合使用,及在用户输入表单保存数据的时候,某个字段不能为空,并且返回数据的时候又不能包含该属性,是不是可以使用组合注解@JsonIngore和@NotNull呢,代码和测试结果如下:

@JsonProperty(value="real_name")private String name ;@JsonIgnore@NotNull(message="idcard is not null")private String idCard;

Postman测试结果如下(条件:idCard及为上述特殊字段,结果报错)

 

经过尝试,小明想到了如下解决方案,代码及测试结果如下:

@JsonProperty(value="real_name")private String name ;@JsonProperty(access=Access.WRITE_ONLY)@NotNull(message="idcard is not null")private String idCard;

Postman测试结果如下(条件:用JsonProperty代替JsonIgnore)

 

成功实现需求。

场景分析四

由于小明公司秉承尽最大努力少使用第三方的资源的原因,项目中关于JsonObject相关的jar都是使用的org.json,并未使用阿里的fastjson,如果项目使用的是fastjson,再使用上述的注解就不起作用了,它有自己的一套注解来解决上述问题,如:@JSONField,具体可参考com.alibaba.fastjson.annotation包。感兴趣的可以查一下。如有问题欢迎交流和分享。

这篇关于关于json传输的过程中字段不对应的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/559040

相关文章

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

oracle 11g导入\导出(expdp impdp)之导入过程

《oracle11g导入导出(expdpimpdp)之导入过程》导出需使用SEC.DMP格式,无分号;建立expdir目录(E:/exp)并确保存在;导入在cmd下执行,需sys用户权限;若需修... 目录准备文件导入(impdp)1、建立directory2、导入语句 3、更改密码总结上一个环节,我们讲了

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

C#下Newtonsoft.Json的具体使用

《C#下Newtonsoft.Json的具体使用》Newtonsoft.Json是一个非常流行的C#JSON序列化和反序列化库,它可以方便地将C#对象转换为JSON格式,或者将JSON数据解析为C#对... 目录安装 Newtonsoft.json基本用法1. 序列化 C# 对象为 JSON2. 反序列化

Python中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja