说说写这篇文章的由来。主要还是根据自己工作所遇到的现状产生的想法。现在随着编程的越来越接口化,我们的数据基本上由原来的entity对象演变成了json格式的数据。我们需要频繁的将json字符串转化成json对象然后一层一层的遍历,根据key来获取对应的值。如果嵌套只有一层两层还好我们通过一两次循环就能取到我们所需要的值,如果嵌套很深的化。我们应该怎么办? 还是一层一层循环去解析然后在一层一层获取,这显然是费力不讨好的活。
由于本人的语文水平一直处于及格水平线上徘徊,所以给大家准备了一个小栗子来说明。
json格式的样例数据
{
"data":{
"order":[
{
"money":"15",
"orders":[
{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"2"
},{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"3"
}
]
},{
"money":"16",
"orders":[
{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"2"
},{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"3"
}
]
},{
"money":"17",
"orders":[
{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"2"
},{
"b1":[
{
"bc1":"1",
"bc2":"2"
},{
"bc1":"2",
"bc2":"3"
}
],
"b2":"3"
}
]
}
],
"info":{
"record":[
{
"a1":"1",
"a2":"2"
},
{
"a1":"1",
"a2":"2"
},
{
"a1":"1",
"a2":"2"
}
]
}
},
"time":{
"addr":"123",
"num":{
"a":"111",
"b":"222"
}
}
}
这其实还不算一个嵌套很深的数据,但是如果我需要去除key b1下面的所有元素,你会如何获取...... 大家不妨动动手中笔,如果是你会怎么解决这个问题,并将其做成一个通用的方法。如果有好的方案,欢迎给我留言,不胜感激。
废话就不多说了,我谈谈自己的戳见。首先我们解析json字符串的肯定直接解析不行的,那样太费事。我们可以借助GSON提供的工具类将json转化成对应的对象,转化后大致的格式是这样的:
根据上面的结构图 我们可以知道 我们如果需要获取到key为b1对应的所有对象 我们需要结果这些key data order orders b1 那么我们何不将这些key用 (.)关联起来组成一个jsonKey = data.order.orders.b1 。有了想法我们就可以动手行动了。这里详细的过程我就不说了,代码的难度不大,只是看我们想不想去做这件事。代码如下:
// 将提取方法进行封装成方法 方便调用
public static Object getKeyJsonQuery(Map<?,?> map ,String jsonKey){
String[] arrs = jsonKey.split("\\.");
Object obj = null;
for(int i=0;i<arrs.length;i++){
if(i==0) {
obj = handle(map, arrs[i]);
}else{
if(obj instanceof Map){
obj = handle((Map<?, ?>) obj,arrs[i]);
}else if(obj instanceof List){
obj = handle((List<Map<?, ?>>) obj,arrs[i]);
}
}
}
return obj;
}
//解析map类型的对象
public static Object handle(Map<?,?> map,String key){
return map.get(key);
}
// 解析list类型的对象
public static Object handle(List<Map<?,?>> listMap,String key){
List<Map<String,Object>> listMaps = new ArrayList<>();
List<Object> lists = new ArrayList<>();
// 这里用到了java8的一个新特性 stream 流
listMap.stream().filter(e->null !=e.get(key) ).map(e->{
//表示既不是map 又不是list类型
if(!(e.get(key) instanceof Map<?,?>) && !(e.get(key) instanceof List<?>) ) {
return lists.add(e.get(key));
}else{
return listMaps.addAll((Collection<? extends Map<String, Object>>) e.get(key));
}
}).collect(Collectors.toList());
// 返回一个不为空的对象并且集合元素大于0 这里为什么不需要考虑两个判断 因为如果两个都为空表示 是空没有获取到值
return lists.size()>0 && !lists.isEmpty() ? lists:listMaps;
}
public static void main(String[] args) throws Exception {
String json = "{\"data\":{\"order\":[{\"money\":\"15\",\"orders\":[{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"2\"},{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"3\"}]},{\"money\":\"16\",\"orders\":[{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"2\"},{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"3\"}]},{\"money\":\"17\",\"orders\":[{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"2\"},{\"b1\":[{\"bc1\":\"1\",\"bc2\":\"2\"},{\"bc1\":\"2\",\"bc2\":\"3\"}],\"b2\":\"3\"}]}],\"info\":{\"record\":[{\"a1\":\"1\",\"a2\":\"2\"},{\"a1\":\"1\",\"a2\":\"2\"},{\"a1\":\"1\",\"a2\":\"2\"}]}},\"time\":{\"addr\":\"123\",\"num\":{\"a\":\"111\",\"b\":\"222\"}}}";
Gson gson = new Gson();
Map<String,Object> map = gson.fromJson(json, Map.class);
System.out.println(map.toString());
String jsonKey = "data.order.orders.b1.bc1";
//String jsonKey = "time.num.a";
//String jsonKey ="data.info";
Object obj = getKeyJsonQuery(map,jsonKey);
System.out.println(obj.toString());
}
附上几张key对应结果
key = data.order.orders.b1.bc1
基本上都可以适应大部分场景,这也算是一个小小的工具方法。个人认为也还是比较有实用价值。其中用到了java8 stream的特性,如果不是很了解,建议去网上查查这方面的只是,stream对于集合的操作的便利性大大的提高了效率。