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数据。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT米粉

你必须了解的反射——反射来实现实体验证

开发工作中,都会需要针对传入的参数进行验证,特别是针对实体进行验证,确保传入的参数格式正确。这里做了一个非常简单的组件进行验证。抛砖引玉,让大家深入思考下反射的...

3147
来自专栏一“技”之长

动态的Objective-C——关于消息机制与运行时的探讨

    Objective-C是一种很优美的语言,至少在我使用其进行编程的过程中,是很享受他那近乎自然语言的函数命名、灵活多样的方法调用方式以及配合IDE流顺畅...

1014
来自专栏草根专栏

使用 C#/.NET Core 实现单体设计模式

本文的概念内容来自深入浅出设计模式一书 由于我在给公司做内培, 所以最近天天写设计模式的文章.... 单体模式 Singleton 单体模式的目标就是只创建一个...

3045
来自专栏cmazxiaoma的架构师之路

关于牛客网的JAVA面试题错题总结以及归纳(1)

1103
来自专栏小鄧子的技术博客专栏

为什么android API 中有很多对象的创建都是使用new关键字

首先,谢邀。 其次,是怎么找到我知乎账号的,我隐藏的这么深(脸红了) 最后,加入了自己的总结概括,让然也可以当成读书笔记来看。

593
来自专栏IT米粉

你必须了解的反射——反射来实现实体验证

日常开发,都是通过API进行前后端的系统对接,对API参数的验证是一个使用率非常高的功能,如果能非常简便的的进行参数验证,能降低代码量,提升工作效率。

3888
来自专栏恰同学骚年

数据结构基础温故-3.队列

在日常生活中,队列的例子比比皆是,例如在车展排队买票,排在队头的处理完离开,后来的必须在队尾排队等候。在程序设计中,队列也有着广泛的应用,例如计算机的任务调度系...

661
来自专栏钟绍威的专栏

SpringMVC类型转换器、属性编辑器PropertiesEditor源码分析CustomDateEditor源码分析TypeConverterDelegate源码分析

对于MVC框架,参数绑定一直觉得是很神奇很方便的一个东西,在参数绑定的过程中利用了属性编辑器、类型转换器 参数绑定流程 参数绑定:把请求中的数据,转化成指定类型...

1878
来自专栏后端之路

从lombok想到的行号问题

背景 lombok 是近几年来声名鹊起的java效率提升利器,对于lombok一直只是在某些开源项目中可以看到。在自身的开发中并未使用。在github上确实使用...

2508
来自专栏程序员宝库

JDK 源码中的一些“小技巧”

均摘选自JDK源码 1 i++ vs i-- String源码的第985行,equals方法中: while (n--!= 0) { if...

3335

扫码关注云+社区