Json从入门到精通

    xiaoxiao2022-07-12  158

    1. json数据类型

    类型描述Number数字型String字符串型Boolean布尔型Array数组Object对象null空值

    (1)json中不区分整数、小数等类型,而统一使用Number来存储数字。

    (2)Array表示数组,以中括号"[]"括起来,元素之间以逗号分隔,元素可以为任意类型。

    (3)Object表示对象,类似于C语言中的结构体,以花括号"{}"括起来,其元素要求为键值对,key必须为String类型的,而value则可为任意类型。key和value之间以":"表示映射关系,元素之间也是以逗号分隔。

    2. 构建json

    2.1 直接构建

    JSONObject obj = new JSONObject(); obj.put(key, value);

    直接构建即直接实例化一个JSONObject对象,而后调用其put()方法,将数据写入。put()方法的第一个参数为key值,必须为String类型,第二个参数为value,可以为boolean、double、int、long、Object、Map以及Collection等。当然,double以及int等类型只是在Java中,写入到json中时,统一都会以Number类型存储。

    范例:

    import org.json.JSONObject; public class JSONObjectSample { public static void main(String[] args) { createJson(); } private static void createJson() { JSONObject obj = new JSONObject(); obj.put("name", "John"); obj.put("sex", "male"); obj.put("age", 22); obj.put("is_student", true); obj.put("hobbies", new String[] {"hiking", "swimming"}); //调用toString()方法可直接将其内容打印出来 System.out.println(obj.toString()); } }

    输出结果为:

    {"hobbies":["hiking","swimming"],"sex":"male","name":"John","is_student":true,"age":22}

    这里可以看到,为了压缩大小以便于更高效地传输,json把所有空格、换行符等空白符全部去掉了。如果想要直观点看其内容,可以用一些在线的json解析器看,例如:http://www.jsoneditoronline.org/

    2.2 使用HashMap构建

    使用HashMap构建json,实际上即先创建好一个HashMap对象并且将数据打包进去,而后在创建JSONObject时将其作为一个参数传进去。

    范例:

    public class JSONObjectSample { public static void main(String[] args) { createJsonByMap(); } private static void createJsonByMap() { Map<String, Object> data = new HashMap<String, Object>(); data.put("name", "John"); data.put("sex", "male"); data.put("age", 22); data.put("is_student", true); data.put("hobbies", new String[] {"hiking", "swimming"}); JSONObject obj = new JSONObject(data); System.out.println(obj.toString()); } }

    2.3 使用JavaBean构建

    相较于前两种方法,实际开发中应用JavaBean构建json的情况更为常见,因为这样代码的重用率更高。

    范例:

    JavaBean:

    public class PersonInfo { private String name; private String sex; private int age; private boolean isStudent; private String[] hobbies; public void setName(String name) { this.name = name; } public void setSex(String sex) { this.sex = sex; } public void setAge(int age) { this.age = age; } public void setStudent(boolean isStudent) { this.isStudent = isStudent; } public void setHobbies(String[] hobbies) { this.hobbies = hobbies; } //getter不能少 public String getName() { return name; } public String getSex() { return sex; } public int getAge() { return age; } public boolean isStudent() { return isStudent; } public String[] getHobbies() { return hobbies; } }

    main:

    import org.json.JSONObject; public class JSONObjectSample { public static void main(String[] args) { createJsonByJavaBean(); } private static void createJsonByJavaBean() { PersonInfo info = new PersonInfo(); info.setName("John"); info.setSex("male"); info.setAge(22); info.setStudent(true); info.setHobbies(new String[] {"hiking", "swimming"}); JSONObject obj = new JSONObject(info); System.out.println(obj); } }

    需要注意一点,JavaBean一定要有getter方法,否则会无法访问存储的数据。

    3. JsonConfig的使用

    3.1 通过jsonconfig实例,对包含和需要排除的属性进行方便的添加或删除

    package lcc.json.test; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date; import net.sf.json.JSONString; public class User { private long id; private String name; private String password; private Date regtime; public User(long id, String name, String password, Date regtime) { super(); this.id = id; this.name = name; this.password = password; this.regtime = regtime; } ... 省略get set方法 } public class Mytest { public static void main(String[] args) { JsonConfig config = new JsonConfig(); config.setExcludes( new String[]{"password"}); User user = new User(12, "梁川川", "json",new Date(System.currentTimeMillis())); System.out.println(JSONObject.fromObject(user, config).toString()); } }

    运行结果:

    {"id":12,"name":"梁川川","regtime":{"date":1,"day":4,"hours":9,"minutes":55,"month":1,"seconds":49,"time":1517450149883,"timezoneOffset":-480,"year":118}}

    3.2 JsonValueProcessor的使用

    这里时间明显不好看,如果转化成2018-05-09格式呢?我们需要使用JsonValueProcessor

    Example: java里面时间类型转换成json数据就成这样了: "createTime":{"date":30,"day":3,"hours":15,"minutes":14,"month":3,"nanos":0,"seconds" :38,"time":1209539678000,"timezoneOffset":-480,"year":108} 期望的结果是"yyyy-mm--dd" 解决方案:使用jsonConfig即可 JsonConfig jsonConfig = new JsonConfig(); jsonConfig.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd HH:mm:ss")); 修改上面的Main方法: package lcc.json.test; import java.text.SimpleDateFormat; import java.util.Date; import net.sf.json.JSONObject; import net.sf.json.JsonConfig; import net.sf.json.processors.JsonValueProcessor; public class Mytest { public static void main(String[] args) { JsonConfig config = new JsonConfig(); config.setExcludes( new String[]{"password"}); User user = new User(12, "梁川川", "json",new Date(System.currentTimeMillis())); config.registerJsonValueProcessor(java.util.Date.class, new JsonValueProcessor() { //自定义日期格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); @Override /** * 处理单个Date对象 */ public Object processObjectValue(String propertyName, Object date,JsonConfig config) { return simpleDateFormat.format(date); } @Override /** * 处理数组中的Date对象 */ public Object processArrayValue(Object date, JsonConfig config) { return simpleDateFormat.format(date); } }); System.out.println(JSONObject.fromObject(user, config).toString()); } }

    3.3 setJsonPropertyFilter 和 PropertyFilter 属性过滤

    package com.xf.test.JsonConfig; import net.sf.json.JSONObject; import net.sf.json.JsonConfig; import net.sf.json.util.PropertyFilter; public class Demo { /** * 必须导入 commons-beanutils-1.8.1.jar * commons-collections-3.2.jar * commons-lang-2.3.jar * commons-logging-1.1.1.jar * ezmorph-1.0.6.jar * json-lib-2.3-jdk15.jar * <p> * 另外如果commons-collections-3.2.jar没有或版本不对的话会出现 * org/apache/commons/collections/map/ListOrderedMap这个异常。 */ public static void test1() { // 1,申明一个String的格式的字符串 String str = "{'String':'JSON','Id':'1','name':'cook','age':'20','address':'shiyan'}"; // 2,实例化一个JSoncongif的对象 JsonConfig jsonConfig = new JsonConfig(); //3.调用setsetExcludes方法 过滤一些属性的值 比喻 “age”,“address”。 jsonConfig.setExcludes(new String[]{"address", "age"}); // 4.将String的字符串转换成JSon格式 JSONObject jsonObject = JSONObject.fromObject(str, jsonConfig); //5,输出json里面的数据 System.out.println(jsonObject); System.out.println(jsonObject.get("String")); System.out.println(jsonObject.get("Id")); System.out.println(jsonObject.get("name")); System.out.println(jsonObject.get("age")); System.out.println(jsonObject.get("address")); } public static void test2() { //1,实例化一个JsonConfig对象 JsonConfig jsonConfig = new JsonConfig(); // 2. 调用 jsonConfig.setJsonPropertyFilter()方法 jsonConfig.setJsonPropertyFilter(new PropertyFilter() { @Override //apply是PropertyFilter的方法 public boolean apply(Object arg0, String arg1, Object arg2) { //arg0是指属性的类 //arg1是指属性的字段 //arg2是指属性的值 //判断条件(arg0是不是当前Emp类并且过滤属性为name的值) return arg0 instanceof Emp && arg1.equals("name"); } }); //3,实例化一个Emp对象 Emp emp = new Emp(1, "谢飞", 22); // 4,将emp对象转换成Json格式 JSONObject jsonObject = JSONObject.fromObject(emp, jsonConfig); //5,输出jsop里面的值 System.out.println(jsonObject); System.out.println("id---" + jsonObject.get("id")); System.out.println("anme---" + jsonObject.get("name")); System.out.println("age---" + jsonObject.get("age")); } public static void main(String[] args) { //Demo.test1(); Demo.test2(); } } package com.xf.test.JsonConfig; public class Emp { private int id; private String name; private int age; public Emp() { } public Emp(String name) { super(); this.name = name; } public Emp(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

    4. 解析json

    解析json主要是基本类型如Number、boolean等,与数组Array。

    基本类型的解析直接调用JSONObject对象的getXxx(key)方法,如果获取字符串则getString(key),布尔值则getBoolean(key),以此类推。

    数组的解析稍微麻烦一点,需要通过JSONObject对象的getJSONArray(key)方法获取到一个JSONArray对象,再调用JSONArray对象的get(i)方法获取数组元素,i为索引值。

    { "hobbies": [ "hiking", "swimming" ], "sex": "male", "name": "John", "is_student": true, "age": 22 } import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.json.JSONArray; import org.json.JSONObject; public class JSONObjectSample { public static void main(String[] args) throws IOException { File file = new File("src/main/java/demo.json"); String content = FileUtils.readFileToString(file); //对基本类型的解析 JSONObject obj = new JSONObject(content); System.out.println("name:" + obj.getString("name")); System.out.println("sex:" + obj.getString("sex")); System.out.println("age" + obj.getInt("age")); System.out.println("is_student" + obj.getBoolean("is_student")); //对数组的解析 JSONArray hobbies = obj.getJSONArray("hobbies"); System.out.println("hobbies:"); for (int i = 0; i < hobbies.length(); i++) { String s = (String) hobbies.get(i); System.out.println(s); } } }

    5.Gson使用

    GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。

    特点: a、快速、高效

          b、代码量少、简洁

          c、面向对象

            d、数据传递和解析方便

    Gson的pom依赖:

    <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.0</version> </dependency>

    Gson的创建方式:

      方式一:Gson gson = new gson();

      方式二:通过GsonBuilder(),可以配置多种配置。

    Gson gson = new GsonBuilder() .setLenient()// json宽松 .enableComplexMapKeySerialization()//支持Map的key为复杂对象的形式 .serializeNulls() //智能null .setPrettyPrinting()// 调教格式 .disableHtmlEscaping() //默认是GSON把HTML 转义的 .create();

    Gson的基本用法:

    注:JavaBean:

    @NoArgsConstructor @AllArgsConstructor @Setter @Getter @ToString @Builder public class PersonJson { private String name; private Integer age; private String hobby; } //hobby是在后面的例子中添加的。要么就name,age两个属性,要么就三个。 //上面的注解是lombok的注解,起到简化Bean类的作用。

    Gson提供了public String toJson(Objcet obj)方法,可以将对象转化为json字符串。

    JavaBean转化为json字符串

    public class IndexTest { PersonJson person; @Before public void prepare() { person = new PersonJson("栗霖",18); } @Test public void index() { Gson gson = new Gson(); System.out.println(gson.toJson(person)); System.out.println("---------------"); Gson gson1 = new GsonBuilder().create(); System.out.println(gson1.toJson(person)); } }

    结果:

    List Map 转化为json字符串

    public class IndexTest { PersonJson person; List<PersonJson> list = new ArrayList<>(); Map<String,PersonJson> map = new HashMap<>(); @Before public void prepare() { person = new PersonJson("栗霖",18); list.add(person); map.put(person.getName(),person); } @Test public void index() { Gson gson = new Gson(); System.out.println("---->List convert json" + gson.toJson(list)); System.out.println("------------------------"); System.out.println("---->map convert json" + gson.toJson(map)); } }

    结果:

     

    Gson提供了public T fromJson(String jsonStr,T.class)方法,可以将json字符串转化为Java对象 

    json字符串转化为JavaBean

    public class SecondTest { @Test public void index() { String jsonStr = "{\"name\":\"栗霖\",\"age\":\"18\"}"; Gson gson = new GsonBuilder().create(); PersonJson p = gson.fromJson(jsonStr,PersonJson.class); System.out.println("---->jsonStr convert javaBean " + p.getName() + " " + p.getAge()); } }

    结果:

    json字符串转化为list集合

    public class SecondTest { @Test public void index() { String listJsonStr = "[{\"name\":\"栗霖\",\"age\":\"18\"},{\"name\":\"栗霖之雨\",\"age\":\"18\"}]"; Gson gson = new GsonBuilder().create(); List<PersonJson> list = gson.fromJson(listJsonStr,new TypeToken<ArrayList<PersonJson>>(){}.getType()); System.out.println("---->listJsonStr convert List " + list); } }

    结果:

    json的抽象基类JsonElemetn:

    JsonNull其实就是Null字段

    public class SecondTest { @Test public void index() { //JsonNull jsonNull = new JsonNull();该方法已经过时 JsonNull jsonNull = JsonNull.INSTANCE; System.out.println("---->jsonNull " + jsonNull); } }

    结果:

    jsonPrimitive可以帮助我们获取带转义字符的字符串。这个就不写了。感觉没啥用到。

    创建JsonObject:

      可以通过addProperty(String,Object)向JsonObject添加属性,跟hashmap类似。

    public class SecondTest { @Test public void index() { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("name","栗霖"); jsonObject.addProperty("age",18); System.out.println("---->create jsonObject " + jsonObject); } }

    结果:

    创建JsonArray

    public class SecondTest { @Test public void index() { JsonArray jsonArray = new JsonArray(); jsonArray.add("a"); jsonArray.add("b"); jsonArray.add("c"); jsonArray.add("d"); System.out.println("---->create jsonArray: " + jsonArray); } }

    结果:

    JsonObject嵌套数组或者说JsonObject嵌套JsonArray

    public class SecondTest { @Test public void index() { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("name","栗霖"); jsonObject.addProperty("age",18); JsonArray jsonArray = new JsonArray(); jsonArray.add("是码农"); jsonArray.add("以前喜欢玩游戏"); jsonArray.add("现在只敢小心积累"); jsonArray.add("只怕突然白了头"); jsonObject.add("status",jsonArray); System.out.println("---->create jsonArray: " + jsonObject); } }

    结果:


     

    Gson注解

    重命名注解:@SerializedName

    当你调用其他服务时,他们返回的json KEY值与你的Bean属性名称不对应怎么办?

    这时候就需要@SerializedName啦。他可以帮助你解决这个问题!

    实体类:

    @NoArgsConstructor @AllArgsConstructor @Setter @Getter @ToString @Builder public class PersonJson { private String name; private Integer age; //这里只是随便举个例子,千万不要用中文!!! @SerializedName(value = "爱好") private String hobby; }

    示例:

    public class SecondTest { JsonObject jsonObject; JsonArray jsonArray; @Before public void index() { jsonObject = new JsonObject(); jsonObject.addProperty("name","栗霖"); jsonObject.addProperty("age",18); jsonArray = new JsonArray(); jsonArray.add("是码农"); jsonArray.add("以前喜欢玩游戏"); jsonArray.add("现在只敢小心积累"); jsonArray.add("只怕突然白了头"); jsonObject.addProperty("爱好",jsonArray.toString()); } @Test public void formal() { Gson gson = new GsonBuilder().create(); PersonJson personJson = gson.fromJson(jsonObject.toString(),PersonJson.class); System.out.println("---->String: " + personJson); } }

    结果:

    @serializedName

    除了value属性外,还可以使用alternate属性,这个值可以替换前面的值,将传入的json进行修改。

    注:value的值不能出现在alternate中,alternate是备选字段。

    @SerializedName(value = "hobby", alternate = {"interest","be fond of"})

    过滤注解@Expose

    注:默认是既可以序列化,也可以反序列化。一定要配合GsonBuilder一起使用

      该注解是加在JavaBean的属性上使用的。

      配合这个使用哦Gson gson = new GsonBuilder().excludeFieldWithoutExposeAnnotation().create();

    有四种使用方式:

      1)不使用@Expose注解等同于@Expose(deserialize = false, serialize = false)不做任何解析

      2)@Expose(deserialize = true, serialize = false)只解析使用,可以反序列化,不可以序列化。

      3)@Expose(deserialize = false, serialize = true)可以序列化,不可以反序列化。

      4)@Expose(deserialize = false, serialize = true)既可以序列化,也可以反序列化。

    注:这里的序列化指:将对象转化为json字符串。反序列化指:将json字符串转化成对象。

    版本控制注解@Since(float v)

    结合GsonBuilder().serVersion(n)使用。当n>=v时,才会解析。

    注:也是加在JavaBean属性上使用的。

    版本控制注解@Util(float v)

    与@Since相反,这次是n<v时才能够解析。

    使用TypeAdapter来实现序列化与反序列化。

    使用TypeAdapter来序列化和反序列化

    代码:

    public class FiveTest { @Test public void index() { Gson gson = new GsonBuilder().create(); TypeAdapter<PersonJson> typeAdapter = gson.getAdapter(PersonJson.class); String json = "{\"name\":\"栗霖\",\"age\":\"18\",\"hobby\":\"我很是很喜欢FromSoftWare的。大爱宫崎英高,赞美太阳\"}"; PersonJson p = new PersonJson("栗霖",18,"混系列忠实粉丝"); System.out.println("---->序列化:是将对象转化为字符串 : " + typeAdapter.toJson(p)); try { System.out.println("---->反序列化:是将字符串转化为对象 : "+ typeAdapter.fromJson(json)); }catch (Exception e) { e.printStackTrace(); } } }

    结果:

     

    Gson的容错机制

    为什么容错:

      如果Bean中定义的是int,但是返回的json对应的是一个""空字串怎么办?这就依赖到了Gson的容错机制。

    1)创建宽松Gson

    遇到问题,停止解析,以防止报错,功能相对较弱。

    Gson gson = new GsonBuilder() .setLenient()//宽松 .create();

    2)自定义TypeAdapter

    该方法更倾向于整体防止出现异常。

    public class ThirdTest { public static class PersonTypeAdapter extends TypeAdapter<PersonJson> { @Override public void write(JsonWriter jsonWriter, PersonJson personJson) throws IOException { jsonWriter.beginObject(); jsonWriter.name("name").value(personJson.getName()); jsonWriter.name("age").value(personJson.getAge()); jsonWriter.name("hobby").value(personJson.getHobby()); jsonWriter.endObject(); } @Override public PersonJson read(JsonReader jsonReader) throws IOException { PersonJson personJson = new PersonJson(); jsonReader.beginObject(); while (jsonReader.hasNext()) { switch (jsonReader.nextName()) { case "name": personJson.setName(jsonReader.nextString()); break; case "age": try { personJson.setAge(Integer.valueOf(jsonReader.nextString())); } catch (Exception e) { } break; case "hobby": personJson.setHobby(jsonReader.nextString()); } } jsonReader.endObject(); return personJson; } } @Test public void index() { Gson gson = new Gson(); String json = "{\"name\":\"栗霖\",\"age\":\"\",\"hobby\":\"篮球吧,读书吧,steam吧\"}"; System.out.println("----> " + json ); try { PersonJson p1 = gson.fromJson(json,PersonJson.class); System.out.println("---->默认解析 " + p1); }catch (Exception e) { System.out.println("---->异常解析,这里json字符串缺失了age的值,真的是怕一转眼就白了头啊" +e); } Gson gson1 = new GsonBuilder().registerTypeAdapter(PersonJson.class,new PersonTypeAdapter()).create(); try { PersonJson p2 = gson1.fromJson(json,PersonJson.class); System.out.println("---->自定义Adapter 默认解析 "+p2); }catch (Exception e) { System.out.println("---->自定义adapter 异常解析" + e); } try { PersonTypeAdapter personTypeAdapter = new PersonTypeAdapter(); PersonJson p3 = personTypeAdapter.fromJson(json); System.out.println("---->自定义Adapter 默认解析 " + p3); }catch (Exception e){ System.out.println("---->自定义Adapter 异常解析 " +e); } } }

    结果:

    3)使用注解jsonAdapter,其实质也是自定义Adapter

      该方法更倾向于某一个属性的保护。

    实体类:

    public class PersonJson { private String name; @JsonAdapter(IntegerTypeAdapter.class) private Integer age; private String hobby; }

    Adapter:

    public class IntegerTypeAdapter extends TypeAdapter<Integer>{ @Override public void write(JsonWriter jsonWriter, Integer integer) throws IOException { jsonWriter.value(integer); } @Override public Integer read(JsonReader jsonReader) throws IOException { int i = 0; try { i = Integer.valueOf(jsonReader.nextString()); }catch (Exception e){} return i; } }

    测试类:

    public class FourTest { @Test public void index() { Gson gson = new Gson(); String json = "{\"name\":\"栗霖\",\"age\":\"\",\"hobby\":\"篮球吧,读书吧,steam吧\"}"; try { PersonJson p1 = gson.fromJson(json,PersonJson.class); System.out.println("---->默认解析 " + p1); }catch (Exception e) { System.out.println("---->异常解析,这里json字符串缺失了age的值,真的是怕一转眼就白了头啊" +e); } try { PersonJson p2 = gson.fromJson(json,PersonJson.class); System.out.println("---->默认解析 " + p2); }catch (Exception e) { System.out.println("---->异常解析" + e); } } }

    结果:

    最新回复(0)