Java 中的 JSON
# 155.Java 中的 JSON
JSON,全称 JavaScript Object Notation,译为 JavaScript 对象表示法,是一种非常常见的数据格式。
# JSON 的概念
JSON 现在多用于存储和交换文本信息的语法,比 XML 更小、更快,更易解析。
JSON 表示数据的一个例子:
{
"name":"张三",
"age":23,
"gender":"男"
}
2
3
4
5
# JSON 语法
基本规则如下:
数据在名称/值对中:JSON 数据是由键值对构成的
键用引号(单双都行)引起来,也可以不使用引号
值的取值类型有如下集中:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在方括号中)
{"persons":[{},{}]}
- 对象(在花括号中)
{"address":{"province":"陕西"....}}
- null
数据由逗号分隔:多个键值对由逗号分隔
花括号保存对象:使用
{}
定义 json 格式方括号保存数组:[]
我们来实践一下,创建一个新的 HTML 文件:01.JSON 数据语法.html
// 1. 定义基本格式
var person = {
"name": "张三",
"age" : 23,
"gender": true
}
console.log(person);
2
3
4
5
6
7
8
可以看到有正常输出,这说明我们语法正确。
第二种:
// 2. 垫套格式,例如JSON数据里有个数组
var personsData = {
persons: [
{"name": "张三", "age" : 23, "gender": true},
{"name": "李四", "age" : 24, "gender": true},
{"name": "王五", "age" : 25, "gender": true}
]
};
console.log(personsData)
2
3
4
5
6
7
8
9
第三种:
// 3. 第三种嵌套格式:数组里定义多个JSON
var personData3 = [
{"name": "张三", "age" : 23, "gender": true},
{"name": "李四", "age" : 24, "gender": true},
{"name": "王五", "age" : 25, "gender": true}
]
console.log(personData3)
2
3
4
5
6
7
# 获取 JSON 里的数据
JS 中有如下方式获取 JSON 的数据:
JSON对象.键名
JSON对象["键名"]
,通过中括号的方式获取,记得加引号数组对象[索引]
- 遍历
代码演示:
JSON对象.键名
:
// 1. 定义基本格式
var person = {
"name": "张三",
"age" : 23,
"gender": true
}
console.log(person.name)
console.log(person["name"])
2
3
4
5
6
7
8
JSON对象["键名"]
// 2。垫套格式,例如JSON数据里有个数组
var personsData = {
persons: [
{"name": "张三", "age" : 23, "gender": true},
{"name": "李四", "age" : 24, "gender": true},
{"name": "王五", "age" : 25, "gender": true}
]
};
console.log(personsData.persons[2].name) //王五
2
3
4
5
6
7
8
9
数组对象[索引]
// 3. 第三种嵌套格式:数组里定义多个JSON
var personsData3 = [
{"name": "张三", "age" : 23, "gender": true},
{"name": "李四", "age" : 24, "gender": true},
{"name": "王五", "age" : 25, "gender": true}
]
console.log(personsData3[1].name) // 李四
2
3
4
5
6
7
遍历
var person = {
"name": "张三",
"age" : 23,
"gender": true
}
for( var key in person){
console.log(key + " : " + person[key])
}
2
3
4
5
6
7
8
9
注意,不能用 person.key 的形式获取 value,因为 key 是一个字符串,而 persion."name"
这样的写法是不对的。
var personsData3 = [
{"name": "张三", "age" : 23, "gender": true},
{"name": "李四", "age" : 24, "gender": true},
{"name": "王五", "age" : 25, "gender": true}
]
for(var i = 0; i < personsData3.length; i++){
var p = personsData3[i];
for ( key in p){
console.log( key + " : " + p[key]);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# JSON 解析器
浏览器和服务器之间经常是需要用 JSON 交换数据的,而在 Java 中,万物皆对象,我们经常需要将一个对象转为 JSON 格式的数据返回给浏览器,此时我们可以用一些第三方的工具类(也叫解析器)帮我们转换;
同时,浏览器发送给服务器 JSON 数据后,经常需要将 JSON 数据转为 Java 对象来操作。
常见的解析器:
- Jsonlib,官方提供的
- Gson,谷歌提供的
- fastjson,阿里巴巴提供的
- jackson,SpringMVC 内置的解析器
# Jackson
今天我们以 jackson 为例,使用步骤:
- 导入 jackson 的相关 jar 包
- 创建 JavaBean
- 创建 Jackson 核心对象 ObjectMapper
- 调用 ObjectMapper 的相关方法进行转换
# 导入依赖
jackson-annotations-2.2.3.jar
jackson-core-2.2.3.jar
jackson-databind-2.2.3.jar
# 创建实体类
我们创建一个 person 类,用来转换为 JSON 数据:
package com.peterjxl.domain;
public class Person {
private String name;
private int age;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 使用 Jackson 来解析 JSON
在 Jackson 中,核心对象是 ObjectMapper
,我们转换对象为 JSON 就是用 ObjectMapper
的方法来转换的。主要是如下方法:
writeValueAsString(obj)
:将对象转为 JSON 字符串writeValue(参数1, obj)
,其中参数 1 是指定 JSON 字符串输出的位置,可以取下面的值:File:将 obj 对象转为 JSON 字符串,并保存到指定的文件中
Writer:将 obj 对象转为 JSON 字符串,并将 JSON 数据填充到字符输出流中
OutputStream:将 obj 对象转为 JSON 字符串,并将 JSON 数据填充到字节输出流中
我们来演示下:
package com.peterjxl.domain;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
public class JacksonTest {
@Test
public void ObjectToJSON() throws Exception{
Person p = new Person();
p.setName("peter");
p.setAge(18);
p.setGender("男");
// 2。创建jackon的核心对象 ObjectMapper
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(p);
System.out.println(json);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
运行结果:
{"name":"peter","age":18,"gender":"男"}
还可以写入到文件中:
mapper.writeValue(new File("Jackson.txt"), p);
mapper.writeValue(new FileWriter("Jackson2.txt"), p);
2
文件内容:
{"name":"peter","age":18,"gender":"男"}
# Jackson 的注解
Jackson 提供了如下属性进行配置:
- @JsonIgnore:排除属性,使用了该注解的属性,转换为 JSON 数据时会被忽略
- @JsonFormat:配置属性值如何格式化,例如
@JsonFormat(pattern = "yyyy-MM-dd")
我们给 Person 类加个日期类型的成员变量:
public class Person {
private String name;
private int age;
private String gender;
private Date birthday;
// 这里省略getter和setter
}
2
3
4
5
6
7
来看看转换后的格式:
@Test
public void ObjectToJSON2() throws Exception{
Person p = new Person();
p.setName("peter");
p.setAge(18);
p.setGender("男");
p.setBirthday(new Date());
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(p));
}
2
3
4
5
6
7
8
9
10
11
运行结果:日期类型被转换为毫秒值
{"name":"peter","age":18,"gender":"男","birthday":1681033967868}
而如果我们加了一个注解:
public class Person {
private String name;
private int age;
private String gender;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birthday;
}
2
3
4
5
6
7
8
再转换的结果:
{"name":"peter","age":18,"gender":"男","birthday":"2023-04-09"}
# Jackson 转换集合
如果转换的是一个 List 集合,也能正常解析吗?可以的。List 会被转换为数组格式,Map 会被转换为对象格式。
List 转 JSON 示例:
@Test
public void ObjectToJSON3() throws Exception{
Person p = new Person("peter", 18,"男", new Date());
Person p2 = new Person("peter2", 19,"男", new Date());
Person p3 = new Person("peter3", 20,"男", new Date());
List<Person> persons = new ArrayList<Person>();
persons.add(p);
persons.add(p2);
persons.add(p3);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(persons));
}
2
3
4
5
6
7
8
9
10
11
12
13
运行结果:
[{"name":"peter","age":18,"gender":"男","birthday":"2023-04-09"},{"name":"peter2","age":19,"gender":"男","birthday":"2023-04-09"},{"name":"peter3","age":20,"gender":"男","birthday":"2023-04-09"}]
Map 转 JSON 示例:
@Test
public void ObjectToJSON4() throws Exception{
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "张三");
map.put("age", "23");
map.put("gender", "男");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(map));
}
2
3
4
5
6
7
8
9
10
运行结果:
{"gender":"男","name":"张三","age":"23"}
# JSON 转 Java
了解即可,用的较少。使用的是方法是 readValue(json字符串数据,Class)
@Test
public void JSONToObject() throws Exception{
// 1. 初始化JSON字符串
String json ="{\"gender\":\"男\",\"name\":\"张三\",\"age\":\"23\"}";
// 2.创建ObjectMapper
ObjectMapper mapper = new ObjectMapper();
// 3.转为Java对象
Person person = mapper.readValue(json, Person.class);
System.out.println(person);
}
2
3
4
5
6
7
8
9
10
11
运行结果:
Person{name='张三', age=23, gender='男', birthday=null}
# 案例:校验用户名是否存在
我们在日常冲浪的时候,有时候需要注册,在输入用户名的时候,有些网站会在输入完后校验是否存在同名的,存在则提示用户更换。这是怎么做的呢?Ajax,在用户输入完后,发送 Ajax 请求给服务器,服务器返回查询结果。例如百度:可以打开控制台观察结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/jquery-3.3.1.min.js"></script>
<script>
// 页面加载完成后
$(function (){
// 给username绑定blur事件
$("#username").blur(function (){
var username = $(this).val()
// 期望服务器响应回的数据格式:
// { "userExsit": true, "msg" : "此用户名太受欢迎,请更换一个"}
// { "userExsit": false, "msg" : "用户名可用"}
$.get("/hello/findUserServlet", {username:username}, function (data){
// 判断userExsit的值
var span = $("#s_username")
if(data.userExist === true){
span.css("color", "red")
span.html(data.msg);
}else {
span.css("color", "green")
span.html(data.msg);
}
}, "json")
})
})
</script>
</head>
<body>
<form>
<input type="text" name="username" id="username" placeholder="请输入用户名"> <br/>
<span id="s_username"> </span>
</form>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
为了简单起见,这里就不查询数据库了,而是直接判断:
package com.peterjxl.ajax;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/findUserServlet")
public class FindUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
Map<String , Object> map = new HashMap<>();
// 1. 获取请求参数
String username = req.getParameter("username");
if("tom".equals(username)){
map.put("userExsit", true);
map.put("msg", "此用户名太受欢迎,请更换一个");
}else{
map.put("userExsit", false);
map.put("msg", "用户名可用");
}
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(), map);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
重启 Tomcat,访问 http://localhost: 8080/hello/JSON/04.register.html,并测试:
特别注意两个点:
在 JS 里,我们需要设置 dataType 为 JSON,不然返回的是一个字符串,通过字符串去获取值是肯定不行的:
data.userExist
,这也是常犯的一个错误。除非服务器设置了 MIME 类型:response.setContentType("application/json;charset=utf-8");
1Servlet 里注意设置编码为 UTF-8