JavaWeb中使用JSON
前言: 最近也是期末了,有好多好多文档和实验报告要交,所以都没啥时间写文,这段时间清闲了,来补一下之前学习时遗漏的一些知识树,话说就没人吐槽这个JSON图标好丑吗?
什么是JSON
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言
*
- JSON 具有自我描述性,更易理解
JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
这里有意思的是,JSON本来是用来表示 JavaScript 对象的一种数据文本格式,但由于它轻量级、易于解析/操作(JavaScript原生支持)的一些特点,渐渐的被很多语言支持也就成了一种标准
为什么使用JSON
在JSON之前,我们通常在网络传输中使用的格式是XML,在我们的印象之中,XML具有很好的可读性,并且格式统一,解析起来也相对比较简单,为什么摒弃掉XML而逐渐的使用起JSON呢?
主要原因在于:JSON比XML更小、更快、更易解析。
- JavaScript原生支持JSON,解析速度相较XML会更快;
- XML解析成DOM对象的时候,浏览器之间会产生差异【例如IE和FireFox】;
- JSON有很多强大的库能够帮助我们更快更简单的完成工作
XML与JSON实例比较
接下来我们通过一个实例的比较来真实的说明一下XML与JSON的区别:
- 使用
XML
表示中国部分省市的数据如下:
<?xml version="1.0" encoding="utf-8" ?> <country> <name>中国</name> <province> <name>黑龙江</name> <citys> <city>哈尔滨</city> <city>大庆</city> </citys> </province> <province> <name>广东</name> <citys> <city>广州</city> <city>深圳</city> <city>珠海</city> </citys> </province> <province> <name>*</name> <citys> <city>台北</city> <city>*</city> </citys> </province> <province> <name>*</name> <citys> <city>乌鲁木齐</city> </citys> </province> </country>
- 使用
JSON
中国部分省市数据如下:
var country = { name: "中国", provinces: [ { name: "黑龙江", citys: { city: ["哈尔滨", "大庆"]} }, { name: "广东", citys: { city: ["广州", "深圳", "珠海"]} }, { name: "*", citys: { city: ["台北", "*"]} }, { name: "*", citys: { city: ["乌鲁木齐"]} } ] }
从编码的可读性来说,
XML
有明显的优势,毕竟人类的语言更贴近这样的说明结构。而JSON
读起来更像是一个数据块,读起来比较费解,不过我们读起来费解的语言,恰恰是适合机器于都的,所以通过JSON
是的索引contry.provinces[0].name
就可以读取到“黑龙江”这个值从编码的手写难度来说,
XML
还是更简单一些,好读也就意味着好写;不过JSON
写出来的字符明显就少很多;去掉空白制表以及换行的话,JSON
就是密密麻麻的有用数据,而XML
却包含很多重复的标记字符。
JSON相比XML的不同之处
- 没有结束标签
- 更短
- 读写的速度更快
- 能够使用内建的 JavaScript eval() 方法进行解析
- 使用数组
- 不使用保留字
对于AJAX应用程序员来说,JSON比XML更快更易使用:
使用XML:
- 读取XML文档
- 使用XML DOM来循环遍历文档
- 读取值并存储在变量中
使用JSON:
- 读取JSON字符串
- 用 eval() 处理JSON字符串
JSON语法
客户端与服务器交换的数据无非就是两种: 数组或者是对象,JSON所表示的数据也就是这两种了
JSON语法是JavaScript语法的子集,在JavaScript中用[]
中括号来表示数组,用{}
大括号来表示对象,JSON也是这样
JSON数组:
[]
中括号里面的内容有些像ArrayList,是一个列表一样的东西
var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName": "Carter" } ];
JSON对象:
{}
大括号里面的东西有些像Map,是一对一对的键值对
var obj = { age:20, str:"wmyskxz", method:function() { alert("我爱学习"); } };
-
注意:
[]
中括号和{}
大括号之间是可以相互嵌套的
解析JSON
在解析JSON对象之前,我们需要首先地来创造一个JSON对象:
<script> var JASONObject = {"name": "我没有三颗心脏", "age": 21}; </script>
使用HTML解析
在HTML中我们可以直接使用.
点号来直接访问JSON对象的属性:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSON学习</title> </head> <body> <p> Name:<span id="name"></span><br> Age:<span id="age"></span><br> </p> <script> var JASONObject = {"name": "我没有三颗心脏", "age": 21}; document.getElementById("name").innerHTML = JASONObject.name; document.getElementById("age").innerHTML = JASONObject.age; </script> </body> </html>
打开网页我们能正确看到如下效果:
但通常情况中,我们拿到和上传的并不是一个真正的JSON对象,而是一串由JSON转换得来的字符串,我们同样在HTML中模拟解析一下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSON学习</title> </head> <body> <p> Name:<span id="name"></span><br> Age:<span id="age"></span><br> </p> <script> var txt = '{"students":[' + '{"name":"我没有三颗心脏0","age":21},' + '{"name":"我没有三颗心脏1","age":21 }]}'; var obj = eval("(" + txt + ")"); document.getElementById("name").innerHTML = obj.students[1].name; document.getElementById("age").innerHTML = obj.students[1].age; </script> </body> </html>
打开网页即可看到如下正确效果:
从前端发送JSON数据到后台
我们这里演示使用AJAX请求的方式来提交JSON数据到后台:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSON学习</title> <!-- 因为不想手动引感觉挺麻烦,引了个菜鸟教程的 --> <script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script> </head> <body> <form> id:<input type="text" id="id" value="123"/><br/> 名称:<input type="text" id="name" value="category xxx"/><br/> <input type="button" value="提交" id="sender"> </form> <div id="messageDiv"></div> <script> $('#sender').click(function () { var id = document.getElementById('id').value; var name = document.getElementById('name').value; var category = {"name": name, "id": id}; var jsonData = JSON.stringify(category); var page = "category"; $.ajax({ type: "put", url: page, data: jsonData, dataType: "json", contentType: "application/json;charset=UTF-8", success: function (result) { } }); alert("提交成功,请在springboot控制台查看服务端接收到的数据"); }); </script> </body> </html>
-
注意: 在上面的例子中,我们使用了
JSON.stringify()
来将一个JSON对象转换成了一串字符串,并且在AJAX中,我们设置了dataType
和contentType
来告知后台我们传输的是一个JSON数据
简单写一个Controller来验证一下吧:
@PutMapping("/category") public void addCategory(@RequestBody Category category) throws Exception { System.out.println("springboot接受到浏览器以JSON格式提交的数据:" + category.getId() + category.getName()); } -----------控制台打印信息:---------- springboot接受到浏览器以JSON格式提交的数据:123 category xxx
- @RequestBody 注解后面讲到,这里只做简单演示
JSON库介绍
引用自:几种常用JSON库性能比较
在后台有许多支持解析JSON的库,目前对于Java开源的JSON类库有许多,下面我们介绍三种比较常用的JSON库,并进行比对说明,它们分别是:
- **Gson(项目地址:https://github.com/google/gson)**
Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
- **FastJson(项目地址:https://github.com/alibaba/fastjson)**
Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
- **Jackson(项目地址:https://github.com/FasterXML/jackson)**
相比json-lib框架,Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。而且Jackson社区相对比较活跃,更新速度也比较快。Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式。
到底使用哪一个JSON库呢?
我看了一些资料,比较印象深刻的是:FastJson在复杂类型的Bean转换Json上会出现一些问题,但是在解析JSON时却是最快的(具体参考:知乎:fastjson这么快老外为啥还是热衷 jackson?)
总结如下:
- FastJson的API设计的最简单,最方便使用,直接使用JSON的两个静态方法即可完成四种操作;而Gson和Jackson都需要new一个对象;
- 数据量大时,使用Jackson;
- 如果有性能要求可以使用Gson/Jackson将bean转换json确保数据的正确性,使用FastJson将Json转换成Bean
三种JSON库简要使用说明
为了导库简单,我在这里都使用Maven搭建的SpringBoot项目来演示,Maven库的地址在这里:https://mvnrepository.com/
在使用之前,我们先来建设一些基础类,用于支持JSON库的使用:
public class Person { private String name; private Integer age; /* getter and setter */ @Override public String toString() { return "名字为" + name + ",年龄" + age; } }
Gson库使用简要说明
(1)Maven依赖:
<!-- Gson库 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency>
(2)使用示例:
@Test public void tester() { Gson gson = new Gson(); /* —————————————————— 准备测试数据 —————————————————— */ Person person1 = new Person(); person1.setName("我没有三颗心脏1"); person1.setAge(21); Person person2 = new Person(); person2.setName("我没有三颗心脏2"); person2.setAge(21); Person person3 = new Person(); person3.setName("我没有三颗心脏3"); person3.setAge(21); List<Person> list = new ArrayList<>(); list.add(person1); list.add(person2); list.add(person3); /* —————————————————— 简单的Bean转为JSON —————————————————— */ String jsonString = gson.toJson(person1); System.out.println("简单的Bean转为JSON:" + jsonString); /* —————————————————— JSON转为简单Bean —————————————————— */ Person personFromJson = gson.fromJson(jsonString, Person.class); System.out.println("JSON转为简单Bean:" + personFromJson.toString()); /* —————————————————— 带泛型的List转JSON —————————————————— */ String jsonStringFromList = gson.toJson(list); System.out.println("带泛型的List转JSON:" + jsonStringFromList); /* —————————————————— JSONz转为带泛型的List —————————————————— */ List<Person> retList = gson.fromJson(jsonStringFromList, new TypeToken<List<Person>>() { }.getType()); for (Person tempPerson : retList) { System.out.println(tempPerson.toString()); } } ------------------结果如下------------------ 简单的Bean转为JSON:{"name":"我没有三颗心脏1","age":21} JSON转为简单Bean:名字为我没有三颗心脏1,年龄21 带泛型的List转JSON:[{"name":"我没有三颗心脏1","age":21},{"name":"我没有三颗心脏2","age":21},{"name":"我没有三颗心脏3","age":21}] 名字为我没有三颗心脏1,年龄21 名字为我没有三颗心脏2,年龄21 名字为我没有三颗心脏3,年龄21
好文推荐及扩展阅读:你真的会用Gson吗?Gson使用指南(一)
FastJson库简要使用说明
(1)Maven依赖:
<!-- FastJson库 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency>
(2)使用示例:
@Test public void tester() { /* —————————————————— 准备测试数据 —————————————————— */ Person person1 = new Person(); person1.setName("我没有三颗心脏1"); person1.setAge(21); Person person2 = new Person(); person2.setName("我没有三颗心脏2"); person2.setAge(21); Person person3 = new Person(); person3.setName("我没有三颗心脏3"); person3.setAge(21); List<Person> list = new ArrayList<>(); list.add(person1); list.add(person2); list.add(person3); /* —————————————————— 简单的Bean转为JSON —————————————————— */ String jsonString = JSON.toJSONString(person1); System.out.println("简单的Bean转为JSON:" + jsonString); /* —————————————————— JSON转为简单Bean —————————————————— */ Person personFromJson = JSON.parseObject(jsonString, Person.class); System.out.println("JSON转为简单Bean:" + personFromJson.toString()); /* —————————————————— 带泛型的List转JSON —————————————————— */ String jsonStringFromList = JSON.toJSONString(list); System.out.println("带泛型的List转JSON:" + jsonStringFromList); /* —————————————————— JSONz转为带泛型的List —————————————————— */ List<Person> retList = JSON.parseObject(jsonStringFromList, new TypeReference<List<Person>>() { }); for (Person tempPerson : retList) { System.out.println(tempPerson.toString()); } } ------------------结果如下------------------ 简单的Bean转为JSON:{"age":21,"name":"我没有三颗心脏1"} JSON转为简单Bean:名字为我没有三颗心脏1,年龄21 带泛型的List转JSON:[{"age":21,"name":"我没有三颗心脏1"},{"age":21,"name":"我没有三颗心脏2"},{"age":21,"name":"我没有三颗心脏3"}] 名字为我没有三颗心脏1,年龄21 名字为我没有三颗心脏2,年龄21 名字为我没有三颗心脏3,年龄21
官方文档:戳这里,据官方说法,FastJson比Gson要快上6倍哦!
Jackson库使用简要说明
(1)Maven依赖:
稍微麻烦一点的是Jackson需要依赖三个包
<!-- jackson库 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency>
(2)使用示例:
@Test public void tester() throws IOException { /* —————————————————— 准备测试数据 —————————————————— */ Person person1 = new Person(); person1.setName("我没有三颗心脏1"); person1.setAge(21); Person person2 = new Person(); person2.setName("我没有三颗心脏2"); person2.setAge(21); Person person3 = new Person(); person3.setName("我没有三颗心脏3"); person3.setAge(21); List<Person> list = new ArrayList<>(); list.add(person1); list.add(person2); list.add(person3); /* ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现的 */ ObjectMapper mapper = new ObjectMapper(); /* —————————————————— 简单的Bean转为JSON —————————————————— */ String jsonString = mapper.writeValueAsString(person1); System.out.println("简单的Bean转为JSON:" + jsonString); /* —————————————————— JSON转为简单Bean —————————————————— */ Person personFromJson = mapper.readValue(jsonString, Person.class); System.out.println("JSON转为简单Bean:" + personFromJson.toString()); /* —————————————————— 带泛型的List转JSON —————————————————— */ String jsonStringFromList = mapper.writeValueAsString(list); System.out.println("带泛型的List转JSON:" + jsonStringFromList); /* —————————————————— JSONz转为带泛型的List —————————————————— */ // List<LinkedHashMap<String, Person>> retList = mapper.readValue(jsonStringFromList, List.class); // for (int i = 0; i < retList.size(); i++) { // Map<String, Person> map = retList.get(i); // Set<String> set = map.keySet(); // for (Iterator<String> it = set.iterator(); it.hasNext();) { // String key = it.next(); // System.out.println(key + ":" + map.get(key)); // } // } /* —————————————————— JSONz转为Array数组 —————————————————— */ Person[] retList = mapper.readValue(jsonStringFromList, Person[].class); for (int i = 0; i < retList.length; i++) { System.out.println(retList[i].toString()); } } ------------------结果如下------------------ 简单的Bean转为JSON:{"name":"我没有三颗心脏1","age":21} JSON转为简单Bean:名字为我没有三颗心脏1,年龄21 带泛型的List转JSON:[{"name":"我没有三颗心脏1","age":21},{"name":"我没有三颗心脏2","age":21},{"name":"我没有三颗心脏3","age":21}] 名字为我没有三颗心脏1,年龄21 名字为我没有三颗心脏2,年龄21 名字为我没有三颗心脏3,年龄21
-
几点注意:
1.由于Jackson底层代码抛出了IOEception,所以我们在调用的时候也需要抛出;
2.Jackson所有的操作都是基于ObjectMapper
在框架中使用JSON
SpingMVC和SpringBoot一样,都能通过注解的方式获取并返回一串JSON格式的数据,我们使用SpringBoot的一段实例程序来实际说明一下:
@RequestMapping("/jsonCategory") @ResponseBody // 该注解表示我们的请求不再交给springmvc处理,而是结合JSON包,将对象解析成JSON字符串 public Category jsonCategory() { return new Category(123, "我没有三颗心脏"); }
我们在浏览器中访问地址:localhost:8080/jsonCategory
,会得到以下JSON数据:
我们也可以使用 @RequestBody
来获取一串JSON数据:
@PutMapping("/category") public void addCategory(@RequestBody Category category) { System.out.println("springboot接受到浏览器以JSON格式提交的数据:" + category.getId() + category.getName()); }
我们在前台使用的是上面用过的用于提交JSON数据的页面,运行能够成功得到结果:
-
注意: Spring4 之后新加入了
@RestController
注解,是@ResponseBody和@Controller的组合注解,用于返回JSON数据。
欢迎转载,转载请注明出处!
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz_javaweb
分享自己的Java Web学习之路以及各种Java学习资料