因为最近公司业务需求,需要两个平台之间的交互,所以大量的接口编程。重点是数据格式的不统一,所以在传输过程中遇到了不少对象转换的问题。
又因为都是json的形式传递数据,所以主要问题也就是json字符串和string,map,list,java对象中间的来回转化。
在这特意写个帖子记录下来中间遇到的问题和解决办法,其实说起来一点也不高深莫测,但是浅显却又复杂,一不小心就容易出个错。这个帖子也算是给自己的自己做一个提示吧。
首先导入依赖:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
String转换成java对象
因为是交互,所以是双方都要提供接口的,其实有一个接口我希望的参数是一个对象,并且我在controller中用@RequestBody注释过了参数(spring boot项目),但是在测试中同事表示调不通这个接口,严厉要去我改成string的形式接受参数,据说是对象无法传输(因为手头忙加上别人的意见,我也懒得看为什么对象传不过来了,只能表示呵呵并且将参数改为string)。
然后涉及到的就是我需要把这个string参数解析成一个对象。
-
首先第一步:把object转换成jsonObject。
因为我这里想把string类型转换jsonObject,所以这个参数就是string类型的。
这个方法是net.sf.json.JSONObject包中的,参数类型就是Object。
JSONObject jsonObject = JSONObject.fromObject(object);
-
第二步:将jsonObject转换成对象。
如图所示吧,这个BaseCar是我自己定义的类,用JSONObject.toBean转化,第一个参数是jsonObject,第二个参数是想转化的类。
BaseCar baseCar = (BaseCar) JSONObject.toBean(jsonObject, BaseCar.class);
这里的转化容易遇到问题,尤其是我这种,只能根据格式来创建接受类的,经常因为一个int和string,一个double和Long的不同,分分钟烦死个人呦,我当时是打个断点一遍遍走,哪个属性没转化成功然后改哪个属性才跑完的。
需要注意的就是这个数据类型真的要求挺严格的,不过稍微好一点的就是报错也很明显,很容易知道是哪个属性出的问题。
至此,一个最简单的字符串转化成java对象就完成了。
复杂嵌套层层转化
刚刚说的String转换成java对象是最简单的一种转化,因为直观而且只有一层,真正复杂的是N层嵌套的转化、比如我从同事接口那获取来的数据。
因为涉及到公司数据,所以在这不截图显示了。简单画一个数据结构图,这个真的是简化简化再简化之后的了。反正对付看吧。
然后我以一个下午的手忙脚乱心烦意燥的经验提醒大家:
遇到这种数据结构千万别着急,一定要一层一层理清楚了再做。不然想要一口吃成胖子或者说一次性解析成功真的要拼脸了。
然后我这里也会一步一步的解析并且附上一些容易出错的点和我犯过的错误。
-
result.getStatusCodeValue() == 200
需要注意的是这个是第一步,也是最基本的一步:判断接口调用是不是成功了!这个不同于你们前后端约定好的200,300或者500等状态,这个是接口调用的返回值,换言之只要你正常的访问了接口,哪怕得到的返回值是300,500那也是一次成功的访问,所以这个result.getStatusCodeValue()也会是200.但是假如接口访问失败,服务端没有起这个接口,或者接口路径写的有问题等等,就会出现各种各种的StatusCodeValue值了,所以我们解析的前提就是这个访问是正常的成功的!也就是以下的所有解析代码都要在
if(result.getStatusCodeValue() == 200)
这个前提下使用。
-
map.get("status")==200
刚刚的数据结构我已经大概画出来了,显而易见也是以键值对的形式存放的,所以我这里如果访问正常就会以map的形式解析
// 将json转化成java数组对象的工具类
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(result.getBody(), Map.class);
这个result.getBody()是指接口的具体返回数据。将此数据用map解析。key如图所示分别是status,data,message.......(我为了简化只写了这几个)
然后我这里的第二步,判断map.get("status")是不是等于200.这个是接口定义的。如果不是二百说明访问有问题,所以不用再往下解析data了。同理是200则正常解析。一句话总结,再往下的解析代码要在
if(map.get("status")==200)
这个前提下使用。
-
多层解析
这个其实很明显,我这个对象里有data,data里还是map形式的user,car....等等,所以还是以map解析
Map<String, Object> map = mapper.readValue(map.get("data"), Map.class);
这里的要注意的点就是多层解析就有多个map实体,反正我之前因为做的心浮气躁的就犯了低级错误,map,map1,map2之类的用混了,最终导致结果错误,要不是断点调试估计肉眼看得看好久能找出来。建议大家别和我一样取名偷懒,每个map的名字写的见名知意一点,要么就是细心专心,我当时因为手头有别的事几个接口写的断断续续的,所以低级错误贼多,现在都心疼和我调试的同事。
继续往下,可以看到data里面的map的key就是car,user之类的,而value则是list。我们根据map的解析继续:
List<Object> list = (List<Object>) map.get("user");
这里注意,因为list里面的格式不定,所以我用Object来接收,这样也避免类型转换的错误。(这里的user是我瞎编的,所以我实际对象不是这么简单的)
同样道理,这里如果要解析的对象很多,list会有很多的话,最好也不要学我一开始list,list1,list2,list3,用着用着就乱了,我这都是血一般的教训。
下面截图是我们接口中的使用,因为涉及一些字段和对象的名字都打了马赛克,反正我是第一遍的接口写的随意但是问题较多,直接就都删了重新写的,条条理理都写的清楚了,往下的逻辑也好写。
而且我这里解析到这步,有的list直接就是对象,就是list里是又套了一层map,所以解析格式不太一样。
反正不管怎么说,解析到这里离我们的最终目的又进了一步了!接着如果我们解析出来的是list<Object>,则直接遍历list,将object转换成对象即可。
不过这里也涉及到你想将Object转换成什么,因为我这里的数据是创建了一个实体来接收,所以这个可以简单看成Object转换成java对象,和我们一开始说的那个方法是一样的写法:
JSONObject jsonObject = JSONObject.fromObject(object); // 将数据转成json字符串
BaseDriver baseDriver = (BaseDriver)JSONObject.toBean(jsonObject, BaseDriver.class);
如果我们这个是用List<Map<String,Object>>来接收的,那么只要遍历list解析map就好了。对了,还要讲这里遇到的一个有趣的问题,就是我同事这里,在这个map里以json字符串的形式给我传了其中一个对象(我也不知道为啥一个简单的接口,里面的数据格式乱七八糟的啥都有,反正这就是考研吧~只能接受啊),反正第一步都是遍历map:
if (list != null && !list.isEmpty() && list.size() != 0) {
for(Map<String, String> map1 :list){
Object object = map1.get("buEntrust");
JSONObject jsonObject = JSONObject.fromObject(object); // 将数据转成json字符串
// 将json转换成对象
BuEntrust buEntrust = (BuEntrust) JSONObject.toBean(jsonObject, BuEntrust.class);
至此就算解析完了吧,手头有点事,先草草结尾,有啥问题的或者用了报错的欢迎提问,我看到了尽量会回复,私信留言都可以。
全文手打这么不容易的写个文如果你觉得用到了理解了留个言点个赞转个发什么的啊