JSON: 是JavaScript Object Notation(JavaScript 对象表示法),它是一种数据交换格式。
JSON 是存储和交换文本信息的语法。类似 XML。
JSON 比 XML 更小、更快,更易解析。
JSON基础结构
因为JSON使用JavaScript语法,所以无需额外的软件就能处理JavaScript中的JSON。
JSON还规定了字符集必须是UTF-8 。为了统一解析,JSON的字符串规定必须用双引号""
,Object的键也必须用双引号""
。
在JSON中,一共就这么几种数据类型:
- number:和JavaScript的number完全一致;
- boolean:就是JavaScript的
true
或false
; - string:就是JavaScript的string;
- null:就是JavaScript的null;
- array:就是JavaScript的Array表示方式——
[]
; - object:就是JavaScript的
{ ... }
表示方式。
把任何JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。
如果我们收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。
JSON对象结构
语法:var obj = {"键" : "值","键" : "值","键" : "值"}
说明:obj 指的是json对象,对象结构以 { 开头,到 } 结束。其中键名和值之间用冒号构成对,键值对用逗号分隔。
注意,这里的键名是字符串,但是值可以是数字、字符串、布尔值、数组、对象和null。
JSON数组结构
语法:var arr = [ {"键名" : "值","键名" : "值"}, {"键名" : "值","键名" : "值"} ]
说明:arr指的是json数组,数组结构是以 [ 开始,到 ] 结束。在JSON数组中,每一对 { } 相当于一个JSON对象。
特殊情况
1. JSON 不能存储 Date 对象。
① 如果要存储 Date 对象,需要将其转换为字符串。之后再将字符串转换为 Date 对象。
var text = '{ "name":"Runoob", "birthday":"2013-12-14"}'; var obj = JSON.parse(text); obj.birthday = new Date(obj.birthday); $('#demo').text("姓名: " obj.name + "生日: " + obj.birthday);
② js将从后台得到的时间戳(毫秒数)转换为日期格式。
var date = new Date( data.time ) ; //括号里的data就是后端传回来的格式有问题的时间数据 dateFormat= date .toLocaleString(); //默认格式为" 年 / 月 / 日 上/ 下午 时:分:秒 "
如果希望转换为" 年-月-日 时:分:秒 "的格式,可以自己定义一个方法。
function add0(m) { return m < 10 ? '0' + m : m; } function formatDate(timeStamp) { let time = new Date(timeStamp), y = time.getFullYear(), m = time.getMonth() + 1, d = time.getDate(), h = time.getHours(), mm = time.getMinutes(), s = time.getSeconds(); return y + '-' + add0(m) + '-' + add0(d) + ' ' + add0(h) + ':' + add0(mm) + ':' + add0(s); //顾名思义,将小于10的时间前面加个0,即9:5:43改成09:05:43 } }
2. JSON 不允许包含函数,但你可以将函数作为字符串存储,之后再将字符串转换为函数。
var text = '{ "name":"Runoob", "alexa":"function () {return 10000;}", "site":"www.runoob.com"}'; var obj = JSON.parse(text); obj.alexa = eval("(" + obj.alexa + ")"); document.getElementById("demo").innerHTML = obj.name + " Alexa 排名:" + obj.alexa();
JSON序列化与反序列化
JSON,大部分是用来处理JavaScript和Web服务端之间的数据交换,把后台Web服务端的数据传递到前台,然后使用JavaScript语法进行处理,例如Ajax等。
由于JSON语法是Javascript语法的子集,JavaScript函数 eval() 可用于将JSON文本转换为JavaScript对象。
前端中的JSON序列化
1. JavaScript对象序列化成JSON格式的字符串
var obj= { name: 'mephisto', age: 14, gender: true, height: 1.65, grade: null, 'middle-school': '\"W3C\" Middle School', skills: ['JavaScript', 'Java', 'Python', 'Lisp'] }; ① var str = obj.toJSONString(); ② var str = JSON.stringify(obj);
要输出得好看一些,可以加上参数,按缩进输出:
JSON.stringify(mephisto, null, ' '); { "name": "mephisto", "age": 14, "gender": true, "height": 1.65, "grade": null, "middle-school": "\"W3C\" Middle School", "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }
第二个参数用于控制如何筛选对象的键值,如果我们只想输出指定的属性,可以传入Array;
JSON.stringify(mephisto, ['name', 'skills'], ' '); { "name": "小明", "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }
还可以传入一个函数,这样对象的每个键值对都会被函数先处理:
function convert(key, value) { if (typeof value === 'string') { return value.toUpperCase(); } return value; } JSON.stringify(xiaoming, convert, ' ');
上面的代码把所有属性值都变成大写:
{ "name": "mephisto", "age": 14, "gender": true, "height": 1.65, "grade": null, "middle-school": "\"W3C\" MIDDLE SCHOOL", "skills": [ "JAVASCRIPT", "JAVA", "PYTHON", "LISP" ] }
如果我们还想要精确控制如何序列化,可以给mephisto
定义一个toJSON()
的方法,直接返回JSON应该序列化的数据:
var xiaoming = { name: 'mephisto', age: 14, gender: true, height: 1.65, grade: null, 'middle-school': '\"W3C\" Middle School', skills: ['JavaScript', 'Java', 'Python', 'Lisp'], toJSON: function () { return { // 只输出name和age,并且改变了key: 'Name': this.name, 'Age': this.age }; } }; JSON.stringify(xiaoming); // '{"Name":"mephisto","Age":14}'
2. JSON格式的字符串反序列化成一个JavaScript对象
var str = '{ "name" : "logo" , "age" : 12}'; ① var obj = eval( "(" + str + ")" ); 必须把文本包含在括号中,这样才能避免语法错误。 ② var obj = JSON.parse(str); ③ var obj = str.parseJSON(); 需要JSON.js文件
JSON.parse() 还可以接收一个函数,用来转换解析出的属性:
var obj = JSON.parse('{"name":"小明","age":14}', function (key, value) { if (key === 'name') { return value + '同学'; } return value; }); console.log(JSON.stringify(obj)); // {name: '小明同学', age: 14}
net.sf.json-lib 解析
Json-lib 需要的 jar 包:
- commons-beanutils-1.8.3.jar
- commons-collections-3.2.1.jar
- commons-lang-2.6.jar
- commons-logging-1.1.1.jar
- ezmorph-1.0.6.jar
- json-lib-2.4-jdk15.jar
依赖:
<dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <!-- 下面两个必须要写,且jdk15不能写成别的 --> <version>2.4</version> <classifier>jdk15</classifier> </dependency>
序列化:
- JavaBean →→→→ JSON格式字符串
Object obj = new Object(); JSONObject jsonObj = JSONObject.fromObject(obj); String str = jsonObj.toString();
- Java数组 / List集合 →→→→ JSON格式字符串
Item[] items = {item1,item2,item3}; List<Person> list = new ArrayList<Person>(); JSONArray jsonArr = JSONArray.fromObject(items); JSONArray jsonArr = JSONArray.fromObject(list); String str = jsonArr.toString();
- Java的Map集合 →→→→ JSON格式字符串
Map<String,Item> map = new HashMap<String,Item>(); JSONObject jsonObject = JSONObject.fromMap(map); //方式一 JSONObject jsonObject = JSONObject.fromObject(map); //方式二 String str = jsonObject.toString();
反序列化:
- JSON格式字符串 →→→→ JavaBean / Map
在将 Json 形式的字符串转换为 JavaBean 的时候需要注意 JavaBean 中必须有无参构造函数。 String jsonObject = "{'name':'李书豪','age':24}"; Person person = (Person) JSONObject.toBean(jsonObject, Person.class); Map<String, Object> map = (Map<String, Object>) JSONObject.toBean(jsonObject, Map.class);
- JSON格式字符串 →→→→ Java数组 / List集合
String jsonStr = " [ …… ] "; JSONArray jsonArr = JSONArray.fromObject(jsonStr); List<Person> person = (List<Person>) JSONArray.toCollection(jsonArr,Person.class);
org.json 解析
依赖:
<dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <!-- 不写下面的版本会报错 --> <version>20170516</version> </dependency>
- 序列化:
JSONObject strJson = new JSONObject(jsonStr); // 传入字符串 JSONObject beanJson = new JSONObject(student); // 传入Bean类型 JSONObject mapJson = new JSONObject(map); // 传入Map类型 JSONArray strJson = new JSONArray(jsonStr); // 传入字符串 JSONArray mapJson = new JSONArray(list); // 传入Collection类型 JSONArray arrayJson = new JSONArray(numlist); // 传入Array类型
- 反序列化:
JSONObject jObject=jsonArray2.getJSONObject(user); Student student=new Student(jObject.getInt("id"), jObject.getString("name"),jObject.getInt("age")); JSONArray jsonArray = new JSONArray(json); for (int i = 0; i < jsonArray.length(); i++) { jsonObject = jsonArray.getJSONObject(i); String name = jsonObject.getString("name"); int age = jsonObject.getInt("age"); }
- JSONObject 根据Key获取Value值
// 创建JSON解析对象 JSONObject obj = new JSONObject(jsonObj); // obj.后面有各种数据类型,根据对象来选择使用的数据类型 String name = obj.getString("name"); // 同理如上,这里的age为Int类型,我们就用对应的类型进行解析 int age = obj.getInt("age");
- JSONObject 添加JSON
//向json对象中添加JavaBean对象或者任意类型数据 JSONObject testObj2 = jsonObject.put("name", "fyj");
- JSONArray 遍历
JSONArray jArray = new JSONArray(jsonArr); for (int i = 0; i < jArray.length; i++) { String string = jArray.getString(i); }
- 向JSONArray中添加JSON对象
JSONObject obj1 = new JSONObject(object1); JSONObject obj2 = new JSONObject(object2); jArray.add(obj1); jArray.add(obj2);
Gson 解析
GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。
主要特点:
- 快速、高效
- 代码量少、简洁
- 面向对象
- 数据传递和解析方便
Gson提供了fromJson() 和toJson() 两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化。
依赖:
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency>
基本类型的序列化
Gson gson = new Gson(); String jsonNumber = gson.toJson(100); // 100 String jsonBoolean = gson.toJson(false); // false String jsonString = gson.toJson("String"); //"String"
Java Bean、List、Map序列化成 Json字符串
Gson gson = new Gson(); String str = gson.toJson(obj); List<PersonJson> list = new ArrayList<>(); Map<String,PersonJson> map = new HashMap<>(); String str = gson.toJson(list); String str = gson.toJson(map)
基本类型的反序列化
Gson gson = new Gson(); int i = gson.fromJson("100", int.class); //100 double d = gson.fromJson("99.99", double.class); //99.99 boolean b = gson.fromJson("true", boolean.class); // true String str = gson.fromJson("str", String.class); // String
json字符串反序列化为JavaBean
Gson gson = new GsonBuilder().create(); PersonJson p = gson.fromJson(jsonStr,PersonJson.class);
json字符串反序列化为List集合
Gson gson = new GsonBuilder().create(); List<PersonJson> list = gson.fromJson(listJsonStr,new TypeToken<ArrayList<PersonJson>>(){}.getType());
Jackson 解析
Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。Jackson所依赖的jar包较少,简单易用并且性能也要相对高些,并且Jackson社区相对比较活跃,更新速度也比较快。
主要特点:
- 容易使用 - jackson API提供了一个高层次外观,以简化常用的用例。
- 无需创建映射 - API提供了默认的映射大部分对象序列化。
- 性能高 - 快速,低内存占用,适合大型对象图表或系统。
- 干净的JSON - jackson创建一个干净和紧凑的JSON结果,这是让人很容易阅读。
- 不依赖 - 库不需要任何其他的库,除了JDK。
- 开源代码 - jackson是开源的,可以免费使用。
依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
创建实体类:
/** * @Description: JSON序列化和反序列化User类 * */ public class User { /** * JSON注解 Jackson提供了一系列注解,方便对JSON序列化和反序列化进行控制,下面介绍一些常用的注解。 * * @JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。 * @JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = "yyyy-MM-dd * HH-mm-ss")。 * @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty("name")。 */ @JsonIgnore private Integer id; @JsonProperty("name") private String trueName; private Integer age; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date birthday; private String email; 。。。省略getset方法、toString()方法等
序列化:
User u1 = new User(); u1.setId(1); u1.setTrueName("curry"); u1.setAge(30); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); u1.setBirthday(dateFormat.parse("1988-9-21")); u1.setEmail("138@163.com"); /** * ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现。 * ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。 * writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。 * writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。 * writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。 * writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。 */ ObjectMapper mapper = new ObjectMapper(); //User对象转Json, String jsonValue = mapper.writeValueAsString(u1); System.out.println(jsonValue); //输出{"age":30,"birthday":"1988-09-20 16:00:00","email":"138@163.com","name":"curry"} //List集合转Json List<User> users = new ArrayList<>(); users.add(u1); users.add(u2); String jsonList = mapper.writeValueAsString(users); System.out.println(jsonList); //输出[{"age":30,"birthday":"1988-09-20 16:00:00","email":"138@163.com","name":"curry"},{"age":29,"birthday":"1989-09-20 16:00:00","email":"123@qq.com","name":"KD"}]
反序列化:
/** * ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。 */ String json = " {\"id\":3, \"name\":\"小明\", \"age\":18, \"birthday\":590774400000, \"email\":\"xiaomin@sina.com\"} "; ObjectMapper mapper2 = new ObjectMapper(); User user = mapper2.readValue(json, User.class); System.out.println(user.toString()); //输出User [id=null, trueName=小明, age=18, birthday=Wed Sep 21 00:00:00 CST 1988, email=xiaomin@sina.com]
FastJson 解析
fastJson是由阿里巴巴开发的一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。fastJson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。
主要特点:
- 快速FAST (比其它任何基于Java的解析器和生成器更快,包括jackson)
- 强大(支持普通JDK类包括任意Java Bean Class、Collection、Map、Date或enum)
- 零依赖(没有依赖其它任何类库除了JDK)
依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.37</version> </dependency>
序列化:
- 序列化Java Bean
String objJson = JSON.toJSONString(Object object); // 缺省情况下fastJSON不序列化值为Null的字段 User user = new User(); user.setTrueName("李四"); user.setAge(24); String userJson = JSON.toJSONString(user); System.out.println(userJson); //{"age":24,"trueName":"李四"} user.setId(111); userJson = JSON.toJSONString(user); System.out.println(userJson); //{"age":24,"id":111,"trueName":"李四"} user.setEmail("98@98"); //传入一个boolean值,可以输出格式化后的 JSON 字符串 userJson = JSON.toJSONString(user,true); System.out.println(userJson); { "age":24, "email":"98@98", "id":111, "trueName":"李四" }
- 序列化list集合
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> map1 = new HashMap<String, Object>(); map1.put("key1", "One"); map1.put("key2", "Two"); Map<String, Object> map2 = new HashMap<String, Object>(); map2.put("key1", "Three"); map2.put("key2", "Four"); list.add(map1); list.add(map2); String listJson = JSON.toJSONString(list); //输出 [{"key1":"One","key2":"Two"},{"key3":"Three","key4":"Four"}]
- 序列化Map
Map<String, Object> map = new HashMap<String, Object>(); map.put("key1", "One"); map.put("key2", "Two"); String mapJson = JSON.toJSONString(map,true);
fastJson 的几个常用特性:
- 日期格式化
fastJson可以直接对日期类型格式化,在缺省的情况下,fastJson会将Date转成long。
String dateJson = JSON.toJSONString(new Date()); System.out.println(dateJson); //1401370199040
使用SerializerFeature特性格式化日期。
String dateJson = JSON.toJSONString(new Date(), SerializerFeature.WriteDateUseDateFormat); System.out.println(dateJson); //"2014-05-29 21:36:24"
也可以指定输出日期格式。
String dateJson = JSON.toJSONStringWithDateFormat(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"); System.out.println(dateJson); //"2014-05-29 21:47:00.154"
- 使用单引号
String listJson = JSON.toJSONString(list, SerializerFeature.UseSingleQuotes); // 输出:[{'key1':'One','key2':'Two'},{'key3':'Three','key4':'Four'}]
- 格式化
String listJson = JSON.toJSONString(list, SerializerFeature.PrettyFormat);
- 输出null字段
String listJson = JSON.toJSONString(map, SerializerFeature.WriteMapNullValue); // {"a":null,"b":1}
- 序列化时写入类型信息
User user = new User(); user.setAge(18); user.setUserName("李四"); String listJson = JSON.toJSONString(user, SerializerFeature.WriteClassName); // 输出结果:{"@type":"User","age":18,"userName":"李四"} // 由于序列化带了类型信息,使得反序列化时能够自动进行类型识别。 将上面的例子反序列化 User user1 = (User) JSON.parse(listJson); System.out.println(user1.getAge()); // 输出18 // 如果User序列化时没有加入类型信息(SerializerFeature.WriteClassName),按照上面的做法就会报错(java.lang.ClassCastException)。
反序列化:
- 对象反序列化
User user1 = JSON.parseObject(userJson, User.class); System.out.println(user1.getTrueName()); System.out.println(user1); // 李四 // User [id=111, trueName=李四, age=24, birthday=null, email=98@98]
- 集合反序列化
List<User> list1 = JSON.parseArray(listJson, User.class);
- Map反序列化
Map<String, Object> map1 = JSON.parseObject(mapJson, new TypeReference<Map<String, Object>>(){});