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的区别:

  1. 使用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>
  1. 使用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中,我们设置了 dataTypecontentType 来告知后台我们传输的是一个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学习资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容