JSON、使用JSON进行数据交换的基础和原理
1. JSON
1.1. JSON
1.1.1. 什么是JSON
JSON即Javascript对象表示法,是一种现在主流的数据交换格式。之所以应用广泛还是由其简单易读所决定的。
简单,只有六种类型的符号 [ ] { } ; ,就可以表示任何种类的复杂对象或数组。
易读,机器解析还是人的阅读都能够从这种格式中快速找到所需要的信息。
1.1.2. 与平台无关的数据交换
JSON作为数据交换的格式与平台种类是无关的。不管服务器使用Java语言、C#语言或其他语言都能够从这种字符串格式转换为具体语言的对象。同样,任何语言也都能将自己的对象转换为JSON的字符串。
1.1.3. 轻量级的解决方案
JSON的轻量级是与XML这种数据交换格式相比,速度更快,文档也更小。XML文件中会包含很多对象的层级关系,解析及转换极不方便,字符更多导致文件过大。而这些弊端JSON都已经克服,简单的符号是的解析更快。
1.2. JSON语法
1.2.1. JSON的结构
使用JSON进行数据交换时,主要有两种结构,一种是使用“名称-值”对儿的形式来表示一个对象,一种是值的有序列表,也就是数组。在这两种结构基础之上,相互之间可以进行嵌套。即对象的值可以是数组或对象,数组中的某个值可以是对象或数组。
不同语言之中的对象、记录、结构、字典、哈希表等都可以作为转换的对象基础结构。
1.2.2. 使用JSON表示一个对象
使用JSON表示一个对象时,基本的语法结构是 以大括号开始,以大括号结尾。大括号之间的各个属性由逗号分隔,每一组属性由属性名和属性值的成对组合实现。如:要表现一个雇员对象可以按如下结构书写:{‘id’:1,’name’:’王小贱’,’age’:24}
所以不管多么复杂的结构,只要看到大括号就代表这个一个对象,至于内部的属性只要保证用逗号分隔即可。
每一组属性在书写时要遵循以下原则:
- 属性名要使用引号引起来
- 属性值的类型可以多样化,包括string、number、true、false、null、object、array
- 如果属性值的类型为字符串,则必须使用引号括起来
只要对象的结构符合语法结构,那么要访问其中某个属性时就可以遵循“对象 . 属性名 ”的格式来访问其中的某个属性值。如上面的雇员对象,想获取name属性的值“王小贱”就可以使用如下的代码实现:
var obj = {‘id’:1,’name’:’王小贱’,’age’:24}; var name = obj . name ;
如果对象的某个属性值依然是对象,那么定义结构如下:
var obj = {‘id’:1 , ’name’:’王小贱’ , ’dep’:{‘depId’:1,’depName’:’财务部’}}; var depName = obj.dep.depName ;
对象属性可以是对象,访问这个对象属性的时候依然遵循“对象.属性名”的方式来获取,上面的对象中obj就是一个对象中还包含对象的结 构,dep是属性名,{‘depId’:1,’depName’:’财务部’}是属性值,即部门属性又包括部门编号、部门名称这两个属性,所以要想访问属 性中的属性使用多级的点格式即可。
1.2.3. 使用JSON表示一个数组
使用JSON表示数组的时候,一定以方括号开始,以方括号结尾。所以只要看到方括号就要想到这是一个数组,数组内的多个值之间用逗号隔开。语法如下:[ value , value , value … ]
value的类型可以是string、number、false、true、null、object、array。
如果要表示3个员工的数组就可以使用如下形式:
var jsonArr = [{‘id’:1 , ’name’:’王小贱’} , {‘id’:2,’name’:’黄小仙’} , {‘id’:3,’name’:’王老头’}];
如果要访问数组中第二个元素的姓名,那么代码如下:
var name = jsonArr[1].name;
数组中的元素依然可以嵌套使用数组,对象的属性也可以嵌套数组,有如下代码:
var jsonObj = {‘id’:1 , ‘name’:’王小贱’ , ‘salary’:[{‘month’:1 , ‘number’:5000},{‘month’:2 , ‘number’:4000 }]};
对于嵌套的数据类型,遵循原则就是:是对象就通过“.”来访问,是数组就通过“[ ] ”下标来访问。针对上面的对象,要想知道员工2月份的工资是多少,访问形式如下: var number = jsonObj.salary[1].number;
2. 使用JSON实现数据交换
2.1. 数据交换
2.1.1. 数据交换原理
JSON作为数据的交换格式,在客户端和服务器端都要有对应的转换过程。如果是客户端请求数据,那么服务器端就将Java对象先转换成 JSON字符串,经响应把字符串传到客户端之后,客户端就会接收到这个转换结果,但JavaScript要求把这个字符串变成对象格式才更方便访问,所以 在客户端的JavaScript代码中又需要将这个JSON字符串变成JavaScript能够识别的对象,这样就完成了从服务器端的对象到客户端对象的 整个转变过程。
同理,如果在客户端填写了数据后想提交给服务器,首先是将客户端数据构造成一个JSON对象字符串,经网络传递到服务器端,服务器端再依据转换规则将JSON字符串变成Java识别的对象。
2.1.2. Java对象转换成JSON
在服务器端对象的转换过程可以使用官方提供的API,JSONObject和JSONArray分别为对象和数组的转换类型。
使用这两个类型进行对象转换时代码如下:
Employee emp = new Employee(1,“王小贱”,“男”); JSONObject obj = JSONObject.fromObject(emp); String jsonStr = obj.toString();
对于数组的转换代码如下:
List<Employee> emps = new ArrayList< Employee >(); for(int i=0;i<3;i++){ Employee s = new Employee (); s.setId(i+1); s.setName("Bear" + i); s.setGender(“男”); emps.add(s); } JSONArray jsonArr = JSONArray.fromObject(emps); String jsonStr = jsonArr.toString();
2.1.3. JSON字符串转换成JS对象
当JSON经传输到达客户端时,需要完成JSON到JavaScript对象的转换,如果使用JS原生的方法进行转换的话,可以使用eval()方法,但需要在JSON的前后连接上左右圆括号,如:
var jsonObj = eval(“(“ + json “)”);
为什么要 eval这里要添加('('+json+')') 呢?
原因在于eval本身的问题。 由于json是以”{}”的方式来开始以及结束的,在JS中,它会被当成一个语句块来处理,所以必须强制性的将它转换成一种表达式。加上圆括号的目的是迫 使eval函数在处理JavaScript代码的时候强制将括号内的表达式(expression)转化为对象,而不是作为语句(statement)来 执行
但是需要注意的是方式eval()方法是动态执行其中字符串(可能是js脚本)的,这样很容易会造成系统的安全问题。所以可以采用一些规避了 eval()的第三方客户端脚本库,如prototype.js里面提供的evalJSON()方法。通过在页面中引入prototype.js文件后就 可以使用这个扩展库。
实现代码如下:
<script type="text/javascript" src="js/prototype-1.6.0.3.js"></script> <script type="text/javascript"> function f1(){ var xhr = getXhr(); xhr.open('get','quoto.do',true); xhr.onreadystatechange=function(){ if(xhr.readyState == 4){ var txt = xhr.responseText; //将json字符串转换成javascript对象或者数组 var arr = txt.evalJSON(); } }; xhr.send(null); } </script>
2.2. 缓存问题
2.2.1. 什么是缓存问题
IE浏览器提供的AJAX对象,在发送GET请求时,会先查看是否访问过该地址,如果改地址已经访问过,那么浏览器不再发送请求
表现在页面终究是,第一次点击某功能会得到数据,但是如果多次反复点击想获取最新数据时页面不会有任何变化,因浏览器发现地址相同而拒绝发出请求。
但这种页面表现只出现在IE浏览器中,Chrom浏览器和Firefox浏览器都能够实现数据的获取和页面的刷新。
2.2.2. 如何解决缓存问题
要想解决缓存问题,就需要欺骗浏览器,让它认为每次请求的地址是不一样的。构建不同的URL需要添加上一个随机数。代码格式如下:
xhr.open(‘get’,’getNumber.do?’+Math.random() , true );
Math.random()可以产生0-1之间的随机数,这样每次都可以生成不一样的地址,让浏览器重新发送请求,以达到数据刷新的效果。
第二种解决缓存问题的方式就是不使用GET请求方式,改成POST提交的话,浏览器不会进行地址的判断。
2.3. 同步问题
2.3.1. 什么是同步问题
同步请求指的是在AJAX对象发出请求后,浏览器要等待响应的回来之后再允许页面继续操作,表现形式就是页面的假死状态。就好像是只有做完一件事以后才能再做下一件事情。而异步是不需要这样的等待的,有种两件事情同时进行的感觉。
2.3.2. 如何发送同步请求
发送同步请求在于open方法的第三个参数,如果填写false则代表同步类型的请求,为true代表异步类型的请求。
代码如下:
xhr.open(‘get’,’check..’,false);
2.3.3. 同步请求的使用场景
同步请求一般应用在表单验证这种必须等待验证返回后才能点击提交这样的情况下。或者是在onunload事件时通知服务器客户端的关闭也可以 用同步请求,有些应用需要知道客户端是否关闭窗口,以此决定是否将服务器端针对该客户端分配的相关资源什么时候释放。如果客户端关闭了浏览器,那么在 onunload事件中可以通知服务器,但是如果不等服务器返回就关掉的话,会不知道是否释放成功,所以通常情况下就是用同步的方式来等待服务器的响应, 在一定程度上能 保证服务器资源的释放。