一、导入依赖
- 如果使用的是SpringBoot则无需导入,SpringBoot近几个版本以内置JackSon
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
二、在Spring中配置Jackson(如果是SpringMVC的话,可能存在乱码问题,所以要进行配置,SpringBoot可跳过此部分)
1、使用xml进行配置
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
2.使用注解配置
- 以下代码添加在Spring配置类(即被@Configuration标注的类)中,且还要添加@EnableWebMvc注解,且继承WebMvcConfigurer
// 配置消息转换器
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(stringHttpMessageConverter());
}
// 配置编码
@Bean
public StringHttpMessageConverter stringHttpMessageConverter(){
return new StringHttpMessageConverter(UTF_8);
}
// 配置jackson消息转换器,虽然不配置仅靠stringHttpMessageConverter也没有乱码,但还是配置一下
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = jackson2ObjectMapperFactoryBean();
mappingJackson2HttpMessageConverter.setObjectMapper(jackson2ObjectMapperFactoryBean.getObject());
return mappingJackson2HttpMessageConverter;
}
3.不进行配置,而在所有的RequestMapping中添加produces属性值为application/json;charset=UTF-8
@RequestMapping(value = "/json1",produces = "application/json;charset=UTF-8")
三、使用Jackson
Jackson的绝大多数操作都需要通过ObjectMapper类来进行
1.基础用法
如下
ObjectMapper mapper = new ObjectMapper();
Friend friend = new Friend("PPG007", 21);
// 写为字符串
String text = mapper.writeValueAsString(friend);
// 写为文件
mapper.writeValue(new File("friend.json"), friend);
// 写为字节流
byte[] bytes = mapper.writeValueAsBytes(friend);
System.out.println(text);
// 从字符串中读取
Friend newFriend = mapper.readValue(text, Friend.class);
// 从字节流中读取
newFriend = mapper.readValue(bytes, Friend.class);
// 从文件中读取
newFriend = mapper.readValue(new File("friend.json"), Friend.class);
System.out.println(newFriend);
2.使用Jackson生成复杂JSON
- 实际开发中,要生成的JSON往往没有对应的实体类,一般使用Map存储键值对然后使用ObjectMapper生成JSON字符串
public void test() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> hashMap = new HashMap<>();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
hashMap.put("editTime",simpleDateFormat.format(new Date()));
hashMap.put("name","PPG007");
hashMap.put("sex","male");
hashMap.put("age",21);
String value = objectMapper.writeValueAsString(hashMap);
System.out.println(value);
}
输出:
{"sex":"male","name":"PPG007","editTime":"2021-07-07 19:27:29","age":21}
这里要注意,如果HashMap中某个键已经是被转换过的JSON字符串了,则再次进行转换会出现引号丢失、多余转义字符等问题,即生成了不标准JSON,在Layui等框架中可能会出现无法解析的问题
像下面这样
public void test() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> hashMap = new HashMap<>();
HashMap<String, String> hashMap2 = new HashMap<>();
hashMap2.put("name","teacher");
hashMap2.put("age","40");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
hashMap.put("editTime",simpleDateFormat.format(new Date()));
hashMap.put("name","PPG007");
hashMap.put("sex","male");
hashMap.put("age",21);
hashMap.put("teacher",objectMapper.writeValueAsString(hashMap2));
String value = objectMapper.writeValueAsString(hashMap);
System.out.println(value);
}
输出为
{"teacher":"{"name":"teacher","age":"40"}","sex":"male","name":"PPG007","editTime":"2021-07-07 19:39:10","age":21}
正确做法应该是在最后一次转换前,所有内容都应该是Java对象,直到最后才生成JSON字符串
public void test() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> hashMap = new HashMap<>();
HashMap<String, String> hashMap2 = new HashMap<>();
hashMap2.put("name","teacher");
hashMap2.put("age","40");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
hashMap.put("editTime",simpleDateFormat.format(new Date()));
hashMap.put("name","PPG007");
hashMap.put("sex","male");
hashMap.put("age",21);
hashMap.put("teacher",hashMap2);
String value = objectMapper.writeValueAsString(hashMap);
System.out.println(value);
}
输出为
{"teacher":{"name":"teacher","age":"40"},"sex":"male","name":"PPG007","editTime":"2021-07-07 19:41:01","age":21}
- 如果要生成JSON列表,则使用List存储HashMap或实体类然后使用ObjectMapper生成JSON即可
public void test() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
HashMap<String, Object> hashMap = new HashMap<>();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
LinkedList<HashMap<String, Object>> hashMaps = new LinkedList<>();
for (int i = 0; i < 5; i++) {
hashMap.put("editTime",simpleDateFormat.format(new Date()));
hashMap.put("name","PPG007");
hashMap.put("sex","male");
hashMap.put("age",20+i);
//这里要深拷贝,如果不使用clone方法,由于传入的是引用,下面的clear方法会清空被引用的HashMap导致list中没有值
hashMaps.add((HashMap<String, Object>) hashMap.clone());
hashMap.clear();
}
String value = objectMapper.writeValueAsString(hashMaps);
System.out.println(value);
}
输出
[{"name":"PPG007","editTime":"2021-07-07 19:31:36","age":20,"sex":"male"},{"name":"PPG007","editTime":"2021-07-07 19:31:36","age":21,"sex":"male"},{"name":"PPG007","editTime":"2021-07-07 19:31:36","age":22,"sex":"male"},{"name":"PPG007","editTime":"2021-07-07 19:31:36","age":23,"sex":"male"},{"name":"PPG007","editTime":"2021-07-07 19:31:36","age":24,"sex":"male"}]
3.使用Jackson解析复杂JSON
如何从一个JSONList解析成对象List呢?
使用readTree方法,遍历其中的JsonNode
JsonNode jsonNode = mapper.readTree(s);
for (JsonNode node : jsonNode) {
System.out.print(node.get("age"));
//asText方法会去掉引号
System.out.print(node.get("name").asText());
System.out.println(node.get("tel").asText());
}
如果JSONList中是严格的对象List,则直接readValue为List也是可以的,但是会失去泛型
在解析不规则JSON时,JsonNode是更好的选择
有如下JSON
{
"data": {
"observe": {
"degree": "24",
"humidity": "89",
"precipitation": "0",
"pressure": "1003",
"update_time": "202107071650",
"weather": "多云",
"weather_code": "01",
"weather_short": "多云",
"wind_direction": "3",
"wind_power": "2"
}
},
"message": "OK",
"status": 200
}
我们要获取其中观察到的天气(当然应该先判断status是否成功)使用JsonNode即可
public void test() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String json = FileUtils.readFileToString(new File("src/main/resources/result.json"), StandardCharsets.UTF_8);
JsonNode jsonNode = objectMapper.readTree(json);
System.out.println(jsonNode.get("data").get("observe").get("weather").asText());
}
当然,上面的不停get可能过于繁琐,下面几种方法更加简单
public void test() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String json = FileUtils.readFileToString(new File("src/main/resources/result.json"), StandardCharsets.UTF_8);
JsonNode jsonNode = objectMapper.readTree(json);
// 返回值是JsonNode
System.out.println(jsonNode.findValue("weather").asText());
// 返回值是JsonNode
System.out.println(jsonNode.findPath("weather").asText());
// 获取父节点
System.out.println(jsonNode.findParent("weather"));
// 返回值是List<JsonNode>
System.out.println(jsonNode.findValuesAsText("weather"));
}
4.JackSon配置日期格式
public void test() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Date date = new Date();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
System.out.println(objectMapper.writeValueAsString(date));
}
5.Jackson常用注解
- @JsonProperty 添加在实体类成员上,在要解析的JSON字符串键值与类成员名字不一致时使用
//将JSON字符串中image_name映射到imageName
@JsonProperty(value = "image_name")
private String imageName;
- @JsonIgnore用于忽略JSON字符串中没有的键,添加这个注解的实体类成员将会为null