使用场景

很多时候我们调用上游接口拿到的返回值是json字符串,如果不存在上游共享的公用返回值类,那么下游可能会直接使用JsonObject之类的动态对象类承接这份数据。这时候对于很深的的属性取值是非常复杂的

我们大概会这样写

String getvalue(String jsonStr){
    JSONObject json =JSONObject.parseObject(jsonStr);
    String d = null;
    //比如我们要取出a.b.c.d,但是我们不确定a是不是null,b是不是null,c是不是ull
    //如果要考考虑对象或者是数组判断的值会更加的多
    JSONObject a = json.getJSONObject("a");
    if( a != null ){
        JSONObject b = json.getJSONObject("b");
        if( b != null ){
            JSONObject c = json.getJSONObject("c");
            if( c != null ){
                d = json.getString("d");
            }
        }
    }
    return d;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

上面这种写法是非常恶心的,尤其是在层次比较多的时候,如果使用jsonPath一切就变得简单了

String getvalue2(String jsonStr){
    return JSONPath.compile("$.a.d.c.d").eval( jsonStr,String.class );
}
  • 1.
  • 2.
  • 3.

哪些框架支持jsonPath?

fastjson是有jsonPath支持的,redis的json类型,mysql的json类型也都有对jsonPath的支持

hutools 的ison格式化也是对jsonPath有支持的,支持程度不如fastjson

jayway 也是对jsonPath有支持的,但是它默认处理方案是路径不存在报错,不好用

fastJson对jsonPath的支持

可以取值的数据源支持json字符串,JSONObject对象,支持普通java对象
JSONPath jsonpath = new JSONPath("$.name");
JSONPath jsonpath2 = new JSONPath("$.a.b.c[1]");


//可以直接取json字符串的数据
String jsonDate = "{\"a\":{\"b\":{\"c\":[1,2,3]}}}";
System.out.println( jsonpath.eval( jsonDate ) );
System.out.println( jsonpath2.eval( jsonDate ) );

//可以直接取对象的数据
Goods goods = new Goods();
goods.setName("zhangsan");
System.out.println( jsonpath.eval( goods ) );
System.out.println( jsonpath2.eval( goods ) );


//可以直接取jsonObject的数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("name","jsonZhangsan");
System.out.println( jsonpath.eval( jsonObject ) );
System.out.println( jsonpath2.eval( jsonObject ) );
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
可以指定返回值数据类型
//需要指定类型
System.out.println("指定类型数据存在:" +  jsonpath.<String>eval( jsonObject,String.class ) );
System.out.println("指定类型数据不存在:" +  jsonpath2.<String>eval( jsonObject,String.class ) );
  • 1.
  • 2.
  • 3.
可以静态方法获取数据

它的内部实现是通过多层Segment去一层一层的去取数据

compile是有模版缓存比直接new JsonPath效率高。

read方法底层也用的evel方法

String read = JSONPath.<String>read(JSONObject.toJSONString(goods), jsonpath.getPath(), String.class);
Object eval = JSONPath.eval(goods, jsonpath.getPath());
        
//这是最基本方法,静态方法JSONPath.<String>read(),JSONPath.eval(),都是调用的它
//JSONPath.compile底层自带缓存,缓存了1024个path,比直接调用 new JsonPath的效率高
//推荐使用这个方法
String eval1 = JSONPath.compile(jsonpath.getPath()).<String>eval(goods, String.class);


//对于多层的jsonPath,实际的做法是一层一层取获取
//private JSONPath.Segment[]
//比如a.b.c.d 会被分成 4个Segment
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
一些常见的方法
取值
//获取属性
String v1 = JSONPath.compile("$.name").<String>eval(jsonObject1, String.class);
System.out.println("eval:" + v1);


//extract比eval用起来复杂,看注释应该比eval出的早
Object v2 = JSONPath.compile("$.name").extract( new DefaultExtJSONParser(jsonObject1.toJSONString()));
System.out.println("extract:" + v2);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
删除,修改,取size,得到keys
//删除
System.out.println("删除前:" + jsonObject1 );
JSONPath.compile("$.name").remove(jsonObject1);
System.out.println("删除后:" + jsonObject1 );

//修改值
JSONPath.compile("$.name").set(jsonObject1,"李四");
System.out.println("修改以后:" + jsonObject1 );

//取size
System.out.println("size1:" + JSONPath.compile("$").size(jsonObject1));
System.out.println("size2:" + JSONPath.compile("$").size(goods));
System.out.println("size3:" + JSONPath.compile("$").size(Arrays.asList(1,2,3)));


//得到所有key
System.out.println("keySet-json对象:" + JSONPath.compile("$").keySet(jsonObject1) );
System.out.println("keySet-对象:" + JSONPath.compile("$").keySet(goods) );
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
判断值和path是否存在
//判断path是否存在
System.out.println("path是否存在:" + JSONPath.compile("$.name").contains(jsonObject1) );


//判断值是否存在
System.out.println("是否存在值"+ JSONPath.compile("$.name").containsValue(jsonObject1,"zhangsan") );
System.out.println("是否存在值"+ JSONPath.compile("$.name").containsValue(jsonObject1,"李四") );
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
输出path
//输出path
String path = JSONPath.compile("$.name").getPath();
System.out.println("path:" + path);
  • 1.
  • 2.
  • 3.
对数组追加值
//数组,和jsonArray都可以
JSONArray array = new JSONArray();
array.add(1);
array.add(2);
array.add(3);
JSONPath.compile("$").arrayAdd(array,4);
System.out.println("arrayAdd:" + array );
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

hutool对jsonPath的支持

/**
     * hutool对jsonnPath的支持
     */
    @Test
    public void hutool_jsonpath(){
        JSONObject obj = JSONUtil.parseObj( Goods.randomGoods() );

        //路径不存在,默认不会报错
        System.out.println( obj.getByPath("$.name.age.name2",String.class) );
        System.out.println( JSONUtil.getByPath(obj,"$.name","") );
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

jayway对jsonPath的支持

jayway是spring-boot-starter自带的jsonPath工具

fastJson对jsonPath的支持_数据

使用例子

/**
     * jayway对jsonnPath的支持
     */
    @Test
    public void jayway_jsonpath(){
        Object read = JsonPath.read(JSONUtil.toJsonStr(Goods.randomGoods()),"$.name");

        //不存在的路径会报错
        //Object read = JsonPath.read(JSONUtil.toJsonStr(Goods.randomGoods()),"$.name.age.name2");
        System.out.println(read);

    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.