JSON学习
JSON学习 Json数据格式回顾 什么是json
JSON:( , JS 对象简谱) 是一种轻量级的数据交换格式。它基于 (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。目前,Json处于数据交换语言的王者地位.
Json数组格式
Json的数据本身是数组,中括号包裹,数组的元素之间逗号分开.数组元素的数据类型没有限制.
var jsonArray = ["元素1","元素2","元素3"]; //定义数组格式json
console.log(jsonArray[0]); //访问json数组的元素
for(var i = 0 ; i < jsonArray.length ; i++){console.log(jsonArray[i]); //遍历数组,访问每个元素
}
Json对象格式
Json的数据本身是对象,大括号包裹.对象采用键值对形式存储,键固定为字符串类型,值是任意类型的数据.键和值使用冒号分开.
var jsonObject = {"k1":"v1","k2":"v2","k3":"v3"}; //定义对象格式json
console.log(jsonObject.k1); //取出键k1对应的值
数组对象相互嵌套格式
数组中的元素是对象
var jsonArray = [{"k1":"v1"},{"k2":"v2"}
]; // 定义数组格式json,数组元素是对象
console.log(jsonArray[0].k1); //访问数组0索引的元素,该元素的键k1对应的值
对象中的值是数组
var jsonObject = {"k1":["元素1","元素2"],"k2":["元素1","元素2"]
}; // 定义对象格式json,键是字符串类型,值是数组
console.log(jsonObject.k1[0]); //访问对象的键是k1,对于的值为数组,数组的0索引元素
你中有我,我中有你
var json = {"k1":["元素1",{"key1":"value1"},{"key2":"value2"} ],"k2":[{"key1":"value1"}]
}; //定义对象格式json,键是字符串,值是数组,数组的元素是对象
console.log(json.k1[1].key1); //访问json对象的键k1,对应的是数组,访问数组的1索引,数组的1索引上的元素是对象,访问key1键对应的值
【1】 介绍
是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 。
的优点
前置准备工作:
准备了2个对象 , User
@Data
public class JsonPojo {private List<Integer> intList;private User user;private String address;private Map<Integer,String> map;
}
@Data
public class User {private String name;private String city;
}
① 对象—> 字符串
方法:
JSON.toJSONString(object)
示例:
JsonPojo pojo = new JsonPojo();User user = new User();user.setCity("湖北");user.setName("武汉");pojo.setUser(user);ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);pojo.setIntList(list);pojo.setAddress("大西安");HashMap<Integer, String> map = new HashMap<>();map.put(1,"1111");pojo.setMap(map);// 使用json序列化String s = JSON.toJSONString(pojo);System.out.println("fastjson序列化结果:"+s);
字符串–> 对象
方法: 第2个参数是要转换为对象的类对象
// 将string解析为 对象
JsonPojo jsonPojo = JSON.parseObject(s, JsonPojo.class);
② list —> 字符串
String intString = JSON.toJSONString(integerArrayList);
字符串—> list
这里有很多种方法来转.
private static void listTest() {ArrayList<Integer> integerArrayList = new ArrayList<>();integerArrayList.add(1);integerArrayList.add(3);// 3.1 方法一: list转stringString intString = JSON.toJSONString(integerArrayList);System.out.println(intString);// 3.2 方法二: string 转回listList list1 = JSON.parseObject(intString, List.class);// 3.3 方法三: string --> list -- 借助TypeReferenceList<Integer> list2 = JSON.parseObject(intString, new TypeReference<List<Integer>>() {});// 3.4 方法四: string --> list List<Integer> list3 = JSONObject.parseArray(intString, Integer.class);// 3.5 方法五: string --> listList<Integer> list4 = JSONArray.parseArray(intString, Integer.class);
}
[注意] : 这里引入的 是包下面的 com...;
③ map–> 字符串
String mapJson = JSON.toJSONString(map);
字符串–> map
private static void mapTest() {HashMap<Integer, String> map = new HashMap<>();map.put(1,"222");String mapJson = JSON.toJSONString(map);System.out.println(mapJson);// 将string 转回 map -- 需要借助 TypeReference 来实现.// map对象中, 会有这个key是 int类型的. 就不是string了Map<Integer, String> mapObject = JSON.parseObject(mapJson, new TypeReference<HashMap<Integer, String>>(){});}
需要注意的是这里的 key 是 类型的, 我们看下它序列化之后是怎么样的???
结果: 打印如下 , 其中 1 仍然是 int类型的.
{1:"222"}
JSON层级关系
JSON 是一个抽象类, 有2个子类, 分别是 +
一个主要是负责对象类的一些API,而另一个则是主要负责数组一类的API
对象使用
我们也可以使用 来获取我们想要的对象
我们可以看到 底层也是通过 map 来存储数据的。
我们可以把一个字符串转为 对象.
// 将string转为 JSONObject
JSONObject jsonObject = JSON.parseObject(s);
通过将java对象转为 , 我们可以看到, 这里面只会有2类对象. 一类是 , 另一类是 , list 的对应的是 , 其他的对应的是 类型的.
【特别注意的一点】: 我们可以看到这里面的一个map, 其中的一个元素, key是int类型的, 此时也被转化为了 类型了。
与之前的map--> 字符串进行比对, 可以发现, 之前直接转字符串时,map中如果key是时 ,那么会保留其 int属性,还是 1 , 而不是 “1”。
继续~~
我们可以直接从 这个对象中获取一些我们想要的数据。
跟map的语法一样,通过key获取对应的value,分为2种,一种是获取的value是基本数据类型, 那么有对应的API
另一种则是获取的仍然是一个对象, 那么就拿到的还是一个 .
value = 基本数据类型
value = 对象, 引用对象类型
JSONObject user1 = jsonObject.getJSONObject("user");
如果你 (“key”) 拿到的是一个具体的值, 而不是一个对象, 那么拿 去接是会直接报错的, 因为类型不同, 当然拿这个方法去使用也是有问题的。
对象使用
后续补充~
【2】
接下来介绍第二种常用的序列化与反序列化的方法
前言:
于 2009 年 5 月首次正式发布,旨在满足快速、正确和轻量级三大宗旨。 是一个成熟稳定的库,它提供了多种不同的方法来处理 JSON,包括在一些简单的用例中使用注释。
提供了三个核心模块。
( -core) 定义了一个低级流式 API 并包括特定于 JSON 的实现。
( -) 包含标准的 注释。
( -) 实现数据绑定和对象序列化。
将模块添加到项目中还会将流式处理和注释模块添加为传递依赖项。
————————————————
版权声明:本文为CSDN博主「西凉的悲伤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
maven依赖如下:
<dependency><groupId>com.fasterxml.jackson.coregroupId><artifactId>jackson-annotationsartifactId><version>2.15.2version>
dependency>
<dependency><groupId>com.fasterxml.jackson.coregroupId><artifactId>jackson-coreartifactId><version>2.15.2version>
dependency>
<dependency><groupId>com.fasterxml.jackson.coregroupId><artifactId>jackson-databindartifactId><version>2.15.2version>
dependency>
如果你是-boot项目,我们可以看到 它其中已经被动引入了这个依赖,因此也可以大概猜出来,使用的一些序列化的方式使用的是 的序列化与反序列化。
@RequestBody @ResponseBody
这2个注解其中就含有将对象转为 json的作用,底层应该就是用的将其序列化 和 反序列化的。
① 对象 --> 字符串
我们需要创建一个 对象 来进行序列化与反序列化的进行.
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(pojo);
private static void objJackson() throws JsonProcessingException {JsonPojo pojo = new JsonPojo();User user = new User();user.setCity("湖北");user.setName("武汉");pojo.setUser(user);ArrayList list = new ArrayList<>();list.add(1);list.add(2);pojo.setIntList(list);pojo.setAddress("大西安");HashMap map = new HashMap<>();map.put(1,"1111");pojo.setMap(map);ObjectMapper mapper = new ObjectMapper();// 将对象--> json字符串String s = mapper.writeValueAsString(pojo);System.out.println(s);JsonPojo jsonPojo = mapper.readValue(s, JsonPojo.class);System.out.println(jsonPojo);}
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
【注意】这里的1是 类型的,而不是 int 类型的,与fastjson的序列化这里是不一样的。需要注意。
字符串–> 对象
JsonPojo jsonPojo = mapper.readValue(s, JsonPojo.class); // redaValue(string src, Class target)
第二个参数就是你想要转换为对象的class对象
和很像
② list --> 字符串
String s = mapper.writeValueAsString(list);
字符串 — > list 方法一: 感觉不太好
// 没有指定list的泛型List jsonPojo = mapper.readValue(s, List.class);
可以看到结果是 反序列化后的结果中对象是以的形式存在的。
方法二: 感觉也不是很好, 有强转
// 可以通过先获取一个指定泛型的 list的 Reader
ObjectReader objectReader = mapper.readerForListOf(User.class);
List<User> users = (List<User>)objectReader.readValue(s,User.class);
方法三: 借助 --推荐
虽然 和 都有 , 但是并非来自于同一个包下面的. 它们都有各自的
// 指定反序列化的泛型 -- 借助 TypeReference
List<User> userList = mapper.readValue(s, new TypeReference<List<User>>() {
});
③ map -->
还是一样的方法
String s = mapper.writeValueAsString(map);
字符串 --> map
// 方法一: 也是没有指定泛型
Map map1 = mapper.readValue(s, Map.class);// 方法二: 指定map泛型
Map<Integer, String> stringMap = mapper.readValue(s, new TypeReference<Map<Integer, String>>() {
});
对象
之对象的使用 -CSDN博客
// 将string读取为 JsonNode 的2种方法.JsonNode jsonNode = mapper.readValue(s, JsonNode.class);JsonNode node = mapper.readTree(s);// 再从jsonnode对象中获取我们想要的对象
和 这个对象还是很像的.
【问题举例】
在前不久遇到的一个问题,发送http请求的时候,报了400。
以下是具体的代码。
去调用
@GetMapping("/mapJson")public String mapJsonTest() throws IOException, URISyntaxException {HashMap<Integer, String> map = new HashMap<>();map.put(1,"1111");map.put(2,"222");map.put(3,"333");String request = httpService.sendRequest2(map);System.out.println(request);return request;}// 发送http请求public static String sendRequest2(Map<Integer, String> map) throws IOException {String url = "http://localhost:8080/mapJsonTest";HttpPut httpRequest = (HttpPut) buildHttpMethod(url);String userEntity = JSON.toJSONString(map);StringEntity stringEntity = new StringEntity(userEntity, "UTF-8");httpRequest.setEntity(stringEntity);HttpResponse response = creatHttpClient().execute(httpRequest);int statusCode = response.getStatusLine().getStatusCode();System.out.println(statusCode);HttpEntity entity = response.getEntity();String result = EntityUtils.toString(response.getEntity(), "UTF-8");return result;}
@PutMapping("/mapJsonTest")public String method2(@RequestBody Map<Integer,String> map){Object o = map.get(1);System.out.println(map);return "map 请求成功";}
然后就报400了, 不知道大家能看出什么问题吗?
这其中的问题就在于序列化和反序列化用的不是同一套东西, 我在反序列化的时候,用的是 , 而对象在 @ 进行反序列化的时候使用的的这一套, 导致其中不匹配, 其中的具体的错误是:
2023-12-17 23:35:36.886 WARN 63116 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('1' (code 49)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('1' (code 49)): was expecting double-quote to start field name at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 3]]
从提示中我们已经很明显的看出来了, 是因为其中一个字段的key是 int类型, 而服务B 期望的是 类型, 类型不匹配导致的错误。
其实在上面写这个map转换的时候, 已经可以发现了这2处的不同之处,当然应该还有其他的不同之处。(注解也是不一样的)
解决办法
我们的最终目的是要让 map中的 int类型变为类型即可。
方法一:
我们上面使用到的 的对象, , 使用它来解决。
String userEntity = JSON.toJSONString(map);// 利用 jsonObject 进行中转一次。JSONObject jsonObject = JSON.parseObject(userEntity);String jsonString = JSON.toJSONString(jsonObject);StringEntity stringEntity = new StringEntity(jsonString, "UTF-8");
仔细看下之前,我们用 JSON.(s) ; 的时候,就可以发现,它把这个int类型的key给你转为了 类型,我们再转为就可以了
我们可以明显看到2次的不一样。
转换之后是不会报错, 成功请求到。
方法二:
那么就是使用同一套序列化和反序列化的方法啦 ,都使用来序列化就好了,也不会有问题的。
这里面还有关于这2套序列化和反序列化的一个注解的坑,搜一下应该是可以看到的。
欢迎各位大佬交流讨论, 指出不足之处, 一起加油~~~