前面提到URL尾巴支持添加请求参数,具体格式形如“参数A名称=A参数值&参数B名称=B参数值”,可是这种格式只能传递简单的键值对信息,不能传递结构化数据,也无法传递数组形式的参数,因而它不适用于需要输入复杂参数的场合。为此人们发明了一种轻量级的数据交换格式JSON,它的数据格式完全独立于编程语言,不但能够表达寻常的键值对信息,还支持表达数组形式的各类参数,从而满足了复杂参数的传输要求。
不过Java的开发包并未提供相应的工具来处理JSON串,为此我们需要在工程中添加第三方JSON解析库,常见的json处理工具有阿里巴巴的FastJson,它的下载页面是http://repo1.maven.org/maven2/com/alibaba/fastjson/,最新的版本已经迭代到了1.2.56。若想在代码中使用FastJson的工具,则需先将它的jar包添加到工程的支持库,右击Eclipse左边项目视图中的工程名称,在右键菜单中依次选择“Build Path”——“Configure Build Path ...”。在弹出的新窗口中单击右边的Libraries选项卡,接着单击右侧的“Add JARs...”按钮,在另一个弹窗中找到fastjson-1.2.56.jar,如下图所示。


然后单击OK按钮,回到前一个弹窗也单击OK按钮,完成FastJson的支持库引入操作。
接下来浏览一个购物订单的JSON串例子,具体内容见下:

{
"user_info":{
"name":"思无邪",
"address":"桃花岛水帘洞123号",
"phone":"15960238696"
},
"goods_list":[
{
"goods_name":"Mate30",
"goods_number":1,
"goods_price":8888
},
{
"goods_name":"格力中央空调",
"goods_number":1,
"goods_price":58000
},
{
"goods_name":"红蜻蜓皮鞋",
"goods_number":3,
"goods_price":999
}
]
}

从以上json串的内容可以梳理出它的基本格式定义,详细说明如下:
1、整个json串由一对花括号包裹,并且内部的每个结构都以花括号包起来;
2、参数格式类似键值对,其中键名与键值之间以冒号分隔,形如“键名:键值”;
3、两个键值对之间以逗号分隔;
4、键名需要用双引号括起来,键值为数字的话则无需双引号,为字符串的话仍需双引号;
5、json数组通过方括号表达,方括号内部依次罗列各个元素,具体格式形如“数组的键名:[元素1,元素2,元素3]”;
由此可见,JSON串的格式定义很简洁,层次结构也很清晰。使用FastJson解析json串更是方便,首先调用JSONObject的parseObject方法,得到某个json串的JSONObject对象,示例代码如下:

		// 根据json串获得JSONObject对象
JSONObject object = JSONObject.parseObject(json);

接着就能对JSONObject对象开展进一步的操作,主要的处理方法说明如下:
getString:获取指定键名的字符串。
getIntValue:获取指定键名的整型数。
getDoubleValue:获取指定键名的双精度数。
getBooleanValue:获取指定键名的布尔值。
getJSONObject:获取指定键名的JSONObject对象。
getJSONArray:获取指定键名的JSONArray数组。注意JSONArray类型派生自清单List,意味着可以把它当作清单一样读写。
put:添加指定的键值对信息。
remove:移除指定键名的键值对。
clear:清空当前的JSONObject对象。
toJSONString:把JSONObject对象转换为字符串。

针对前述的购物订单json串,为了有效地保存解析后的订单信息,有必要定义几个相应的实体类。比如要定义一个用户信息类,该类的定义代码如下所示:

//定义一个用户信息
public class UserInfo {
public String name; // 用户姓名
public String address; // 收货地址
public String phone; // 联系号码
}

再定义一个商品项信息类,该类的定义代码如下所示:

//定义一项商品信息
public class GoodsItem {
public String goods_name; // 商品名称
public int goods_number; // 商品数量
public double goods_price; // 商品价格
}

最后定义外层的购物订单信息类,该类的定义代码如下所示:

//定义一次购物订单信息
public class GoodsOrder {
// 用户信息
public UserInfo user_info = new UserInfo();
// 购买的商品清单
public List<GoodsItem> goods_list = new ArrayList<GoodsItem>();
}

定义好了这些实体类,即可将JSONObject对象中的各个数据解析并填入购物订单对象,完整的json解析代码示例如下:

	// 把json字符串解析到对应的实体对象
private static GoodsOrder testParserJson(String json) {
// 创建一个购物订单对象
GoodsOrder order = new GoodsOrder();
// 根据json串获得JSONObject对象
JSONObject object = JSONObject.parseObject(json);
// 从JSONObject对象中获取键名为user_info的用户信息json对象
JSONObject user_info = object.getJSONObject("user_info");
// 从用户信息json对象中获取键名为name的字符串
order.user_info.name = user_info.getString("name");
// 从用户信息json对象中获取键名为address的字符串
order.user_info.address = user_info.getString("address");
// 从用户信息json对象中获取键名为phone的字符串
order.user_info.phone = user_info.getString("phone");
System.out.println(String.format("用户信息如下:姓名=%s,地址=%s,手机号=%s",
order.user_info.name, order.user_info.address, order.user_info.phone));
// 从JSONObject对象中获取键名为goods_list的商品信息json数组
JSONArray goods_list = object.getJSONArray("goods_list");
for (int i=0; i<goods_list.size(); i++) { // 遍历商品信息数组
GoodsItem item = new GoodsItem(); // 创建一项商品对象
// 从json数组获取下标为i的商品json对象
JSONObject goods_item = (JSONObject) goods_list.get(i);
// 从商品json对象中获取键名为goods_name的字符串
item.goods_name = goods_item.getString("goods_name");
// 从商品json对象中获取键名为goods_number的整型数
item.goods_number = goods_item.getIntValue("goods_number");
// 从商品json对象中获取键名为goods_price的双精度数
item.goods_price = goods_item.getDoubleValue("goods_price");
System.out.println(String.format("第%d个商品:名称=%s,数量=%d,价格=%f",
i+1, item.goods_name, item.goods_number, item.goods_price));
order.goods_list.add(item); // 往商品清单中添加指定商品对象
}
return order; // 返回解析后的购物订单对象
}

运行上述的解析代码,观察到以下的购物订单日志,可见成功实现了json串到对象的解析操作:

用户信息如下:姓名=思无邪,地址=桃花岛水帘洞123号,手机号=15960238696
第1个商品:名称=Mate30,数量=1,价格=8888.000000
第2个商品:名称=格力中央空调,数量=1,价格=58000.000000
第3个商品:名称=红蜻蜓皮鞋,数量=3,价格=999.000000

注意到商品订单json串跟GoodsOrder定义的数据结构一一对应,不管是参数名称还是参数类型全部吻合,如此一来就能运用FastJson的自动转换绝技,整个自动转换只有两次代码调用:第一次调用JSONObject的parseObject方法,获得json串对应的JSONObject对象;第二次调用JSONObject的toJavaObject方法,依次填写上一步骤的JSONObject对象,以及待转换的实体类型如GoodsOrder.class。下面便是将json串自动转换成实体对象的代码例子:

		// 根据json串获得JSONObject对象
JSONObject object = JSONObject.parseObject(json);
// 把JSONObject对象中的信息一一转成购物订单信息
GoodsOrder order = (GoodsOrder) JSONObject.toJavaObject(object, GoodsOrder.class);

哇噻,这个自动转换功能不要太好用哟,实乃开发者的一大福音。反过来,把某个实体对象转换成对应的json串,也只需短短一行代码就搞定了,调用JSONObject的toJSONString方法即可,具体转换代码示例如下:

		// 把购物订单对象转换成json字符串
String json = JSONObject.toJSONString(order);

当然,有时候并不需要把整个实体对象都转换为json串,而是提取该对象的部分信息再封装成json串,这样的话,还是按照惯例逐步往json串添加键值对信息,也就是需要封装的数据才要put进JSONObject对象。下面是根据购物订单对象逐步生成json串的代码例子:

	// 根据购物订单对象逐步拼接生成json字符串
private static String testGenerateJson(GoodsOrder order) {
// 创建一个准备保存购物订单的JSONObject对象
JSONObject object = new JSONObject();
// 创建一个准备保存用户信息的JSONObject对象
JSONObject user_info = new JSONObject();
// 往用户信息json对象中添加键名为name的姓名信息
user_info.put("name", order.user_info.name);
// 往用户信息json对象中添加键名为address的地址信息
user_info.put("address", order.user_info.address);
// 往用户信息json对象中添加键名为phone的号码信息
user_info.put("phone", order.user_info.phone);
// 往购物订单json对象中添加键名为user_info的用户信息
object.put("user_info", user_info);
// 创建一个准备保存商品项的JSONArray数组
JSONArray goods_list = new JSONArray();
// 遍历购物订单里的各项商品
for (GoodsItem item : order.goods_list) {
// 创建一个准备保存商品信息的JSONObject对象
JSONObject goods_item = new JSONObject();
// 往商品信息json对象中添加键名为goods_name的名称信息
goods_item.put("goods_name", item.goods_name);
// 往商品信息json对象中添加键名为goods_number的数量信息
goods_item.put("goods_number", item.goods_number);
// 往商品信息json对象中添加键名为goods_price的价格信息
goods_item.put("goods_price", item.goods_price);
goods_list.add(item); // 往json数组中添加JSONObject对象
}
// 往购物订单json对象中添加键名为goods_list的商品项信息
object.put("goods_list", goods_list);
return object.toJSONString(); // 把JSONObject对象转换为json字符串
}


更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(一百零八)JSON串的定义和解析的更多相关文章

  1. Java开发笔记(一百零九)XML报文的定义和解析

    前面介绍了JSON格式的报文解析,虽然json串短小精悍,也能有效表达层次结构,但是每个元素只能找到对应的元素值,不能体现更丰富的样式特征.比如某个元素除了要传输它的字符串文本,还想传输该文本的类型. ...

  2. Java开发笔记(三十七)利用正则串分割字符串

    前面介绍了处理字符串的常用方法,还有一种分割字符串的场景也很常见,也就是按照某个规则将字符串切割为若干子串.分割规则通常是指定某个分隔符,根据字符串内部的分隔符将字符串进行分割,例如逗号.空格等等都可 ...

  3. Java开发笔记(六十二)如何定义函数式接口

    前面介绍了Lambda表达式的用法,从实践中发现它确实极大地方便了开发者,然而不管是匿名内部类还是Lambda表达式,所举的例子都离不开各类数组的排序方法,倘使Lambda表达式仅能用于sort方法, ...

  4. Java开发笔记(六十九)泛型类的定义及其运用

    前面从泛型方法的用法介绍到了泛型的起源,既然单个方法允许拥有泛化的参数类型,那么一个类也应当支持类级别的泛化类型,例如各种容器类型ArrayList.HashMap等等.一旦某个类的定义代码在类名称后 ...

  5. Java开发笔记(序)章节目录

    现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...

  6. Java开发笔记(三十八)利用正则表达式校验字符串

    前面多次提到了正则串.正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了 ...

  7. Java开发笔记(四十五)成员属性与成员方法

    前面介绍了许多数据类型,除了基本类型如整型int.双精度型double.布尔型boolean之外,还有高级一些的如包装整型Integer.字符串类型String.本地日期类型LocalDate等等,那 ...

  8. Java开发笔记(六十三)双冒号标记的方法引用

    前面介绍了如何自己定义函数式接口,本文接续函数式接口的实现原理,阐述它在数组处理中的实际应用.数组工具Arrays提供了sort方法用于数组元素排序,可是并未提供更丰富的数组加工操作,比如从某个字符串 ...

  9. Java开发笔记(七十三)常见的程序异常

    一个程序开发出来之后,无论是用户还是程序员,都希望它稳定地运行,然而程序毕竟是人写的,人无完人哪能不犯点错误呢?就算事先考虑得天衣无缝,揣着一笔巨款跑去岛国买了栋抗震性能良好的海边别墅,谁料人算不如天 ...

随机推荐

  1. 05-Flutter移动电商实战-dio基础_引入和简单的Get请求

    这篇开始我们学习Dart第三方Http请求库dio,这是国人开源的一个项目,也是国内用的最广泛的Dart Http请求库. 1.dio介绍和引入 dio是一个强大的Dart Http请求库,支持Res ...

  2. 定时任务 Scheduled quartz

    在项目应用中往往会用到任务定时器的功能,比如某某时间,或者多少多少秒然后执行某个骚操作等.spring 支持多种定时任务的实现,其中不乏自身提供的定时器.接下来介绍一下使用 spring 的定时器和使 ...

  3. L1434滑雪

    一,看题 1,这个长度怎么算的. 从它自己数,可以走下去的位置. 2,这个题的衣服怎么披上去呀. 3,搜索目标,状态. 肯定要用坐标,不然怎么搜索. 4,在前期还是多写把. 5,我靠这个点还是随机的& ...

  4. 通过三层交换机实现不同VLAN间的通信

    主机的IP地址以及子网掩码已列出,下面将讲解如何配置利用三层交换机来实现不同VLAN间的相互通信 SW1的命令: en  //进入特权模式 conf  t   //全局模式 vlan 10    // ...

  5. react的3种组件

    推荐阅读:https://www.jianshu.com/p/2726b8654989 1. createClass 已不推荐使用,这里不再多讲.但你仍需要了解它,因为你可能会接触到一些旧项目,或者一 ...

  6. linux常用命名汇总:自用,持续更新

    1.查看磁盘空间大小 df -hl 查看磁盘剩余空间 df -h 查看每个根路径的分区大小 du -sh [目录名] 返回该目录的大小 du -sm [文件夹] 返回该文件夹总M数 du -h [目录 ...

  7. fluent将出口温度赋值给入口

    Fluent版本:Fluent18.2 首先我们启动Fluent 然后按照正常的流程进行模型缩放,材料的设置,边界条件的设置等等,然后初始化. 在完成了算例的初始化以后 (define (OutToI ...

  8. plsql 如何导入excel数据?

      oracle 导入excel数据? 通过plsql实现 1.准备工作 Excel中的字段名称,必须和表结构字段一 一对应 下面以tdoctor_apply表为例,进行演示 表结构 Excel表数据 ...

  9. 刷题记录:2018HCTF&admin

    目录 刷题记录:2018HCTF&admin 一.前言 二.正文 1.解题过程 2.解题方法 刷题记录:2018HCTF&admin 一.前言 经过一个暑假的学习,算是正经一条web狗 ...

  10. python @classmethod和@staticmethod区别

    python 类方法和静态方法区别 python @classmethod和@staticmethod区别 Python中至少有三种比较常见的方法类型,即实例方法,类方法.静态方法.它们是如何定义的呢 ...