JSON解析以及GSON简明使用

作者: rabbitknight | 来源:发表于2017-04-15 11:40 被阅读378次
    json头图

    我的博客:http://southtree.cn

    何为JSON

    JSON为JavaScript Object Notation的简称,是一种用于轻量级的数据交换语言,是用了存储和交换文本信息的语法。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,目前很多主流的编程语言都支持JSON。
    说到JSON就不得不提到xml,与XML想比,JSON占用更小、速度更快,更易解析。JSON不可用于配置文件,仅仅作为传输信息来使用。

    JSON基本语法规则

    下面是几个JSON中的基本也是最重要的概念,JSON也就这几个概念

    对象

    一个对象一个对象以{开始,并以}结束。

    数组

    JSON另外一个常用的概念是数组,在键值对中的值或者对象中有时候并不可能是一个简单的值,有时候则可能是数组。数组或有序列表,使用[,]来表示。

    键值对

    在对象中通常包含不止一个"键-值"对。键值对以{"名称":"值"}的形式书写,如果是多对键值对则用分隔。键值对的一个名称是一个字符串; 一个值可以是一个字符串,一个数值,一个对象,一个布尔值,一个有序列表,或者一个null值。


    JSON基本解析实例

    一个简单的小例子

    这里是我从wiki中直接拿过来的一个例子,我觉得非常的好,就拿来直接用。这是一个名为 Jhon Smith的“电话簿”。我们一行行来看。

    {   //①最外层是一个JSON对象,{}中间的为这个对象的内容。
         "firstName": "John",  //②一个键值对,名称为firstName,值为John,用逗号隔开键值对
         "lastName": "Smith",  //同②,略
         "sex": "male",        //同②,略
         "age": 25,            //同②,略
         "address":  //③一个键值对,名称为address,值为一JSON对象
         {
             "streetAddress": "21 2nd Street",  //同②,略
             "city": "New York",                //同②,略
             "state": "NY",                     //同②,略
             "postalCode": "10021"              //同②,略
         },
         "phoneNumber"://④一个键值对,名称为phoneNumber,但是值是JSON数组。
         [  //⑤这里是数组的开始,数组的大小为2,内容为2个对象,数组元素之间使用,隔开。
             {  //⑥数组中第一个元素,为一JSON对象
               "type": "home",
               "number": "212 555-1234"
             },
             {
               "type": "fax",
               "number": "646 555-4567"
             }
         ]
     }
    

    既然文章叫做JSON解析,上面都是论述,总得有个具体的解析吧,那么下面我使用JAVA来常识解析上面的小例子。

    //JAVA中json包的引用我就不说了。
    String json=response.body().string;  //假设从服务拿出来的json字符串,就是上面的内容
    JSONObject personObj = new JSONObject(json); //①创建一个名为person的JSONObject类型。
    
    //②下面分别取出 最外层JSONObject包裹的firstName、lastName等字符串
    System.out.println(personObj.getString("firstName"));
    System.out.println(personObj.getString("lastName"));
    System.out.println(personObj.getString("sex"));
    System.out.println(personObj.getInt("age"));
    
    //③下面是取出 最外层JSONObject包裹的名称为address的JSONObject
    JSONObject addressObj = personObj.getJSONObject("address");
    
    //④下面是取出 addressObject中的streetAddress等对应的字符串
    System.out.println(addressObj.getString("streetAddress");
    System.out.println(addressObj.getString("city");
    System.out.println(addressObj.getString("state");
    System.out.println(addressObj.getString("postalCode");
    //⑤下面是取出 最外层JSONObject包裹的名称为phoneNumber的JSONArray
    JSONArray phoneNumberArray = personObj.getJSONArry("phoneNumber");
    
    //⑥下面是利用循环 读取phoneNumberArray 中的信息
    for(int i = 0;i < phoneNumberArray.lenth(); i++){
        JSONObject tempObj = phoneNumberArray.getJSONObject(i);
        System.ouy.println(tempObj.getString("type"));
        System.ouy.println(tempObj.getString("number"));
        
    }
    
    

    实例

    和风天气api返回json结果

    这里的实例引用了和风天气api的例子,和风天气的是我做课程作业需要使用到的,也是我接触的第一个实际开发过程中使用的例子。
    这是我直接从服务器拿回来的json的数据,我第一次看,感觉十分的复杂 - -。

    {"HeWeather5":[{"aqi":{"city":{"aqi":"66","pm10":"82","pm25":"38","qlty":"良"}},"basic":{"city":"常熟","cnty":"中国","id":"CN101190402","lat":"31.658156","lon":"120.74852","update":{"loc":"2017-04-04 16:51","utc":"2017-04-04 08:51"}},"daily_forecast":[{"astro":{"mr":"11:41","ms":"00:51","sr":"05:42","ss":"18:19"},"cond":{"code_d":"104","code_n":"305","txt_d":"阴","txt_n":"小雨"},"date":"2017-04-04","hum":"61","pcpn":"0.0","pop":"0","pres":"1020","tmp":{"max":"20","min":"15"},"uv":"7","vis":"16","wind":{"deg":"141","dir":"东南风","sc":"微风","spd":"5"}},{"astro":{"mr":"12:41","ms":"01:45","sr":"05:41","ss":"18:20"},"cond":{"code_d":"104","code_n":"305","txt_d":"阴","txt_n":"小雨"},"date":"2017-04-05","hum":"75","pcpn":"2.3","pop":"71","pres":"1015","tmp":{"max":"20","min":"16"},"uv":"8","vis":"14","wind":{"deg":"145","dir":"南风","sc":"微风","spd":"3"}},{"astro":{"mr":"13:41","ms":"02:32","sr":"05:40","ss":"18:20"},"cond":{"code_d":"306","code_n":"305","txt_d":"中雨","txt_n":"小雨"},"date":"2017-04-06","hum":"81","pcpn":"7.5","pop":"100","pres":"1010","tmp":{"max":"22","min":"13"},"uv":"5","vis":"10","wind":{"deg":"189","dir":"东北风","sc":"微风","spd":"7"}}],"hourly_forecast":[{"cond":{"code":"100","txt":"晴"},"date":"2017-04-04 19:00","hum":"62","pop":"0","pres":"1019","tmp":"17","wind":{"deg":"142","dir":"东南风","sc":"3-4","spd":"18"}},{"cond":{"code":"103","txt":"晴间多云"},"date":"2017-04-04 22:00","hum":"72","pop":"0","pres":"1018","tmp":"16","wind":{"deg":"148","dir":"东南风","sc":"3-4","spd":"18"}}],"now":{"cond":{"code":"104","txt":"阴"},"fl":"18","hum":"49","pcpn":"0","pres":"1019","tmp":"19","vis":"8","wind":{"deg":"144","dir":"东南风","sc":"3-4","spd":"16"}},"status":"ok","suggestion":{"air":{"brf":"中","txt":"气象条件对空气污染物稀释、扩散和清除无明显影响,易感人群应适当减少室外活动时间。"},"comf":{"brf":"舒适","txt":"白天不太热也不太冷,风力不大,相信您在这样的天气条件下,应会感到比较清爽和舒适。"},"cw":{"brf":"不宜","txt":"不宜洗车,未来24小时内有雨,如果在此期间洗车,雨水和路上的泥水可能会再次弄脏您的爱车。"},"drsg":{"brf":"较舒适","txt":"建议着薄外套、开衫牛仔衫裤等服装。年老体弱者应适当添加衣物,宜着夹克衫、薄毛衣等。"},"flu":{"brf":"易发","txt":"相对于今天将会出现大幅度降温,空气湿度较大,易发生感冒,请注意适当增加衣服。"},"sport":{"brf":"较适宜","txt":"阴天,较适宜进行各种户内外运动。"},"trav":{"brf":"适宜","txt":"天气较好,风稍大,但温度适宜,总体来说还是好天气。这样的天气适宜旅游,您可以尽情享受大自然的风光。"},"uv":{"brf":"最弱","txt":"属弱紫外线辐射天气,无需特别防护。若长期在户外,建议涂擦SPF在8-12之间的防晒护肤品。"}}}]}
    

    使用工具格式化

    当我使用工具将这串字符格式化后更加清晰可读了。

    JSON格式化后

    从图中可以看出清楚的看出整个和风天气json的结构,左边是格式化后代码,右边是一个树状图结构。
    首先在整个结构的最外层是一个键值对,名称为HeWeather5(因为是x5版本),值为一JSON数组类型且这个数组仅含有一个JSONObject类型的元素。
    接着,在这个JSONObject下面有7个键值对,名称分别是"aqi"(城市空气质量状况),"basic"(城市基础信息),"daily_forecast"(三天的日预报),"hourly_forecast"(每小时的预报),"now"(现在的天气情况),"status"(返回消息的状态),"suggestion"(建议信息)。他们对应着或是几组JSONObject或是JSONArray信息的值,甚至再接着嵌套多次信息。那么我们只要根据形势进行相应的展开就好了。
    下面,我将做示范。
    别想了!这个嵌套我要写老久,我好菜。明天试试

    //占坑
    

    拓展

    引子

    那么,当处理这些json嵌套的时候,首先要进行对数据的建模,然后解开这些嵌套,然后把相应的值给填进去。但当我们遇到一个更复杂的json时,这个工作就很是繁琐,所以下面就引入了很是方便的办法。

    GSON使用

    简介

    Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。
    下面是我在Android 中使用GSON根据上述的和风天气的例子,进行解析的过程。

    导包

    首先使用GSON需要导包,因为使用Android Studio的原因,只需要在app的gradle中的dependencies依赖中添加:

    compile 'com.google.code.gson:gson:2.7'
    

    创建POJO类

    接着根据实际,需要创建POJO类,根据分析后的json代码,当我们把第一层解开后,其实是一个JSONObject嵌套6个JSONObject和一个键值对的情况。那么我们根据实际需要(用到什么取什么或者是全取),取了aqi,basic等对应的5几个JSONObject类。下面单独拿出来几个进行讲解。

    例子①

    这边是经过格式化和tree化的aqi相关的json原码,注意两个红框处。


    aqi
    //①Aqi.java
    public class Aqi {
        public AqiCity city;
        public class AqiCity{
            public String aqi;
            public String pm25;
        }
    }
    

    在上述代码中,创建一个POJO类,其中仅有一个,名为city的内部类AqiCity成员变量,其中内部类AqiCity有两个公有变量:aqi和pm25。

    总结一下,每当JSONObject的内部有一个JSONObject,就需要在POJO类内部创建一个内部类并添加一个相应成员变量,该成员变量名应该和json键值对的键名相一致

    下面这个图可以粗略的看出对应关系。


    json与pojo类对应关系

    例子②

    这边是经过格式化和tree化的basic相关的json原码,注意两个红框处。


    basic
    //②Basic.java
    public class Basic {
        @SerializedName("city")
        public String cityName;
        
        @SerializedName("id")
        public String weatherId;
        
        public Update update;
        public class Update{
            @SerializedName("loc")
            public String UpdateTime;
        }
    }
    

    在例子①中POJO类的变量名称和json的键值对的名称都是一样的,那么在上面的例子中,并不对应,那么这时就需要使用注解的方式:添加一个@SerializedName("city")进行注解。
    但是如果我如果是不同服务器发出的json,仅仅只是键名不同,那么我的POJO类又该怎么处理呢?那么将注解这样写:

    @SerializedName(value = "cityName", alternate = {"cityname", "city_name"})
    

    总之就是,如果 POJO对象/变量 想要和json中不一致,就需要注解

    例子③

    这边是经过格式化的json原码,注意两个红框处。


    weather
    //③Weather.java
    public class Weather {
        public String status;
        public Basic basic;
        public Aqi aqi;
        public Now now;
        public Suggestion suggestion;
        @SerializedName("daily_forecast")
        public List<Forecast> forecastList;
    }
    
    

    Weather.java是将这6个JSONObject和1个键值对嵌套在一起的POJO类,但是我们在嵌套的时候,又会遇到一个问题:daily_forecast对应的是一个JSONArray,JSONArray的每一个元素又是一个JSONObject这时候应该怎么做呢?
    根据上面的代码,可以看出这里使用了List<>,使用java的list的泛型来构造。即,JSONArray型变量需要使用List创建并根据元素类型,选择是否要用泛型

    总结三点:

    1. 每当JSONObject的内部有一个JSONObject,就需要在POJO类内部创建一个内部类并添加一个相应成员变量,该成员变量名应该和json键值对的键名相一致。
    2. 如果 POJO对象/变量 想要和json中不一致,就需要注解。
    3. JSONArray型变量需要使用List创建并根据元素类型,选择是否要用泛型。

    JSON转化为GSON

    最后,只需要将获取的json转化为gson就可以了,这里用到了gson的fromJson方法。

    public static Weather handleWeatherResponse(String response){
        try{
        //因为最外面仍有一个JSONObject所以,只需要手动把它解开接行了
        JSONObject jsonObject = new JSONObject(response);
        JSONArray jsonArray = jsonObject.getJSONArray("HeWeather5");
        String weatherContent = jsonArray.getJSONObject(0).toString();
        //fromJson方法需要包含两个参数,第一个为json代码,第二个为创建的POJO类
        return new Gson().fromJson(weatherContent,Weather.class);
        }catch (Exception e){
            e.printStackTrace();
         }
            return null;
        }
    
    

    如果正常,这个函数就会返回一个Weather类型的值,此时我们需要的参数都包含在里面了!

    One More Thing : Gsonformat

    1. 重复大量的POJO创建工作是一件很伤脑经的事情,这里我们引入一个Android Studio的插件:Gsonformat,使用它就可以很方便的构造模型。
      这里不做过多叙述了,点击这个链接查看Gsonformat的配置以及使用
    2. 本篇博文参考你真的会用Gson吗?Gson使用指南(一) - 简书。是一篇非常好的参考gson使用指南。
    3. 推荐几款实用的Android Studio 插件 - 简书

    相关文章

      网友评论

        本文标题:JSON解析以及GSON简明使用

        本文链接:https://www.haomeiwen.com/subject/cbynattx.html