什么是 JSON,JSON和Java对象的互相转换,一个小案例
最近学习了 AJAX 技术, 由于 AJAX 技术广泛地采用 JSON 为数据传递的格式,所以又去粗略的学习了一下 JSON
1. 概念
1.1 引入
英文全称为 JavaScript Object Notation (中文:JavaScript对象表示法)
JSON 是存储和交换文本信息的语法。类似于 XML。
JSON 比 XML 更小、更快,更易解析。
在 Java 中,我们可以去创建对象来封装信息,比如张三,23岁。
class Test {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");
p.setAge(23);
p.setGender("男");
}
}
class Person {
private String name;
private int age;
private String gender;
public Person(String name, int age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
这样我们就使用了 Java 对象封装了这些零散的数据。在以后需要使用这些数据的时候,直接调用该对象当做参数,直接传递这些数据。
所以,JavaScript 中零散的数据怎么办呢?
我们就拥有了JSON。
1.2 什么是JSON
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言 *
- JSON 具有自我描述性,更易理解
var p = {"name" : "张三", "age" : 23, "gender" : "男"};
这种表示方法我们就成为 JSON。
JSON现在多用于存储和交换文本信息的语法,在网络中进行数据的传输
2. 语法
2.1 基本规则
-
数据在名称 / 值对中:JSON数据是由键值对构成的
-
使用引号(单双都行)引起来,也可以不使用。
-
值的取值类型:
-
数字 (整数或者浮点数)
-
字符串(在双引号中)
-
逻辑值(true 或 false)
-
数组(在方括号中)
{"person":[{},{}]}
-
对象(在花括号中)
{"address":{"province":"江苏"....}}
-
null - 少见不常用
-
-
-
数据有逗号分隔:多个键值对由逗号分隔
-
花括号保存对象:使用 { } 来定义 JSON 格式
-
方括号保存数据: [ ]
2.2.1 使用的例子:
<script>
// 1.定义基本格式
var person = {"name": "张三", "age": 23, "gender": true};
alert(person);
// 2.嵌套格式 {} - > []
var persons = {
"persons": [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
]
};
alert(persons)
// 3. 嵌套格式 [] -> {}
var ps = [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
]
</script>
2.2 获取数据
- json 对象.键名
- json 对象[“键名”]
- 数组对象[索引]
<script>
// 1.定义基本格式
var person = {"name": "张三", "age": 23, "gender": true};
alert(person);
// 获取 name 的值
var name = person.name;
var name2 = person["name"];
alert(name);
alert(name2);
// 2.嵌套格式 {} - > []
var persons = {
"persons": [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
]
};
alert(persons)
var name2 = persons.persons[2].name;
alert(name2);
// 3. 嵌套格式 [] -> {}
var ps = [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
]
var name3 = ps[2].name;
alert(name3);
</script>
对于 json 对象中的数据,除了使用上述的几种方法,当我们需要获取 json 数组中的对象的时候,我们可以使用for循环。
<script>
var persons = {
"persons": [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
]
};
var ps = [
{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": false},
{"name": "王五", "age": 25, "gender": true}
];
// 获取 person 对象中的所有的键和值
for(var i=0; i<persons.persons.length; i++) {
for(var key in persons.persons[i]) {
document.write(key + ":" + persons.persons[i][key]);
document.write("<br/>");
}
}
// 获取 ps 对象中的所有值
for(var i=0; i<ps.length; i++) {
for(var key in ps[i]) {
document.write(key + ":" + ps[i][key]);
document.write("<br/>");
}
}
</script>
3. JSON 数据和 Java 对象的相互转换
在我们将 JSON 和 Java 之间相互转化的时候(客户端和服务器端的数据交互),我们会使用 JSON 解析器。
什么是解析器?解析器就是封装好的一些工具类。
常见的解析器:Jsonlib,Gson,fastjosn,jackson
这次我们使用的是 jackson,因为 jackson 是 spring 框架中自带的。
3.1 JSON 转化为 Java 对象 - 和 3.2 的步骤基本一样,不再赘述
-
使用步骤:
- 导入 jackson 的相关 jar 包
- 创建 jackson 和新对象 ObjectMapper
- 调用 ObjectMapper 的相关方法来进行转换
- readValue(json字符串数组, Class)
-
实例代码:
@Test public void test5() throws IOException { // 1. 初始化 JSON 字符串 String json = "{\"name\":\"张三\",\"age\":23,\"gender\":\"男\"}"; // 2. 创建 ObjectMapper 对象 ObjectMapper mapper = new ObjectMapper(); // 3. 转化为 Java 对象 Person 对象 Person person = mapper.readValue(json, Person.class); System.out.println(person); } // Person{name='张三', age=23, gender='男'}
3.2 Java 转化为 JSON 对象
-
使用步骤:
-
导入 jackson 的相关 jar 包
-
创建 jackson 和新对象 ObjectMapper
-
调用 ObjectMapper 的相关方法来进行转换
-
转换方法:
writeValue(参数1, obj)
- 参数1:
- File : 将 obj 对象转化为 JSON 字符串,并保存到指定的文件中
- Writer:将 obj 对象转换为 JSON 字符串,并 json 数据填充到字符输出流中
- OutputStream:将 obj 对象转化为 json 字符串,并将数据填充到字节输出流中
writeValueAsString(obj) : 将对象转为json字符串
- 参数1:
-
注解:
- @JsonIgnore:排除属性(在后续转换成 json 格式数据时,忽略有注释的属性,选择要注释的属性,可以将注释标注在需要注释的属性上)
- @JsonFormat:属性值格式化
-
-
-
示例代码:
-
使用步骤的实例代码
import cn.itcast.domain.Person; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test; import java.io.File; import java.io.FileWriter; public class JacksonTest { // Java 对象转为 JSON 字符串 @Test public void test1() throws Exception { // 1. 创建 Person 对象 Person p = new Person(); p.setAge(23); p.setName("张三"); p.setGender("男"); // 2. 创建 Jackson 的核心对象 ObjectMapper ObjectMapper mapper = new ObjectMapper(); // 3. 转换 String json = mapper.writeValueAsString(p); System.out.println(json); // {"name":"张三","age":23,"gender":"男"} // writeValue : 将数据写到 d 盘的 a.txt 文件中 mapper.writeValue(new File("d://a.txt"), p); // writeValue : 将数据关联到 Writer 中 mapper.writeValue(new FileWriter("d://b.txt"), p); } }
-
使用注释的实例代码
- @JsonIgnore
import com.fasterxml.jackson.annotation.JsonIgnore; public class Person { @JsonIgnore // 忽略该属性 private Date birthday; // get and set 方法不给出 }
- @JsonFormat
import com.fasterxml.jackson.annotation.JsonFormat; import java.util.Date; public class Person { @JsonFormat(pattern = "yyyy-MM-dd") private Date birthday; }
-
复杂 Java 对象转换
-
List:数组。
@Test public void test3() throws Exception{ // 1. 创建 Person 对象 Person p1 = new Person(); p1.setAge(23); p1.setName("张三"); p1.setGender("男"); p1.setBirthday(new Date()); Person p2 = new Person(); p2.setAge(23); p2.setName("张三"); p2.setGender("男"); p2.setBirthday(new Date()); Person p3 = new Person(); p3.setAge(23); p3.setName("张三"); p3.setGender("男"); p3.setBirthday(new Date()); // 创建 List 集合 List<Person> ps =new ArrayList<>(); ps.add(p1); ps.add(p2); ps.add(p3); ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.writeValueAsString(ps)); }
-
Map:对象的格式是一致的。
@Test public void test4() throws Exception { Person p1 = new Person(); p1.setAge(23); p1.setName("张三"); p1.setGender("男"); p1.setBirthday(new Date()); Person p2 = new Person(); p2.setAge(23); p2.setName("张三"); p2.setGender("男"); p2.setBirthday(new Date()); Person p3 = new Person(); p3.setAge(23); p3.setName("张三"); p3.setGender("男"); p3.setBirthday(new Date()); // 创建 map 对象 Map<String, Person> map = new HashMap<>(); map.put("员工1: ", p1); map.put("员工2: ", p2); map.put("员工3: ", p3); ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.writeValueAsString(map)); }
-
-
4. 案例 - 校验用户名是否存在
以上为百度注册时的注册页面,并不是这次案例的最终结果
注意点:
- 服务器响应的数据,在客户端使用时,想要当做 json 数据格式使用
- $.get(type) : 最后一个参数设置为 “json”
- 在服务器端设置 MIME 类型。 tomcat 为 “application/json;charset=utf-8”
以下为这次试验的代码:
html 页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<script src="js/jquery-3.4.1.min.js"></script>
<script>
// 在页面加载完成后
$(function () {
// 给 username 绑定 blur 时间
$("#username").blur(function () {
// 获取 username 文本输入框的值
var username = $(this).val();
// 发送 ajax 请求
// 期望服务器响应回的数据格式是:{"userExist" : true, "msg" : "用户名已存在"}
// {"userExist" : false, "msg" : "用户名可用"}
$.get("findUserServlet", {username: username}, function (data) {
// 判断 userExist 键的值是否为 true
var span = $("#s_username");
if (data.userExist) {
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" id="username" name="username" placeholder="请输入用户名">
<span id="s_username"></span>
<br/>
<input type="password" name="password" placeholder="请输入密码"><br/>
<input type="submit" value="注册"><br/>
</form>
</body>
</html>
servlet 代码:
package cn.itcast.web.servlet;
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(name = "FindUserServlet", urlPatterns = "/findUserServlet")
public class FindUserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 1. 获取用户名
String username = request.getParameter("username");
// 2. 调用 service 层判断用户是否存在
// 期望服务器响应回的数据格式是:{"userExist" : true, "msg" : "用户名已存在"}
// {"userExist" : false, "msg" : "用户名可用"}
Map<String, Object> map = new HashMap<String, Object>();
if ("tom".equals(username)) {
// 存在
map.put("userExist",true);
map.put("msg", "用户名已存在");
}else{
// 不存在
map.put("userExist",false);
map.put("msg", "用户名可用");
}
// 将 map 转为 json
ObjectMapper mapper = new ObjectMapper();
// 并传递给服务器端
response.getWriter().write(mapper.writeValueAsString(map));
}
}