摘要
SpringBoot返回Json数据中null值处理,将字符串类型null值转换为"",将集合数组类型null值转换为[],将原始数据类型null值转换为0,将布尔类型null值转换为false,将实体对象null值转换为{}。
SpringBoot返回Json数据中null值处理,将字符串类型null值转换为"",将集合数组类型null值转换为[],将原始数据类型null值转换为0,将布尔类型null值转换为false,将实体对象null值转换为{}。
Spring boot默认采用jackson进行序列化,通常会出现返回给前端的对象中包含的属性值为null的情况,如果将null返回给前端,前端还需要额外判断返回值是否为null;还有一种方式是将为null的属性不展示给前端,这就造成前端还需要判断属性是否存在,增加前端的工作。
现在提供了一种后端处理返回对象中属性为null的处理方法:
String、Date 为null 则返回"";
Integer、Double、Float为null,返回0;
List、Set为null,返回[];
Map为null,返回{}
若要实现该逻辑,只需要添加一个configuration,在configration中继承jackson序列化对象,然后重写其属性为null时的序列化逻辑即可,代码如下:
package com.example.demo.aop; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonStreamContext; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.util.ReflectionUtils; /** * @author 帝眼未来-帮回家 * 处理响应报文中,属性为Null时的自定义返回值 * String、Date:“” * Integer、Double、Float:0 * List、Set:[] * Map:{} * Boolean:false */ @Slf4j @Configuration public class JacksonConfig { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { JsonStreamContext outputContext = jsonGenerator.getOutputContext(); //获取到被序列化的对象(包含的所有的属性) Object currentValue = outputContext.getCurrentValue(); //获取当前对象中被序列化的属性 String currentFeildName = outputContext.getCurrentName(); //匹配牛逼的首字母大写问题 currentFeildName = currentFeildName.substring(0,1).toLowerCase()+currentFeildName.substring(1); // 一个被序列化的对象找到了,这个当前序列化的属性也找到了,所以如果借用反射方式可以获取当前的类型 if (currentValue != null) { Field findField = ReflectionUtils.findField(currentValue.getClass(), currentFeildName); if (findField == null) { log.info("当前属性名称:[{}],没有找到对应的实体类中的属性", currentFeildName); } // 获取字段的类型 Class<?> filedType = findField.getType(); // 这里开始写入数据 //log.info("属性:[{}]的类型为:[{}]" ,currentFeildName, filedType.getName()); switch (filedType.getName()) { case "java.lang.String" : jsonGenerator.writeString(""); break; case "java.lang.Boolean" : jsonGenerator.writeBoolean(false); break; case "java.lang.Integer" : jsonGenerator.writeNumber(0); break; case "java.lang.Double" : case "java.lang.Float" : jsonGenerator.writeObject(0.0); break; case "java.util.Set" : jsonGenerator.writeObject(new HashSet<>()); break; case "java.util.Map" : jsonGenerator.writeObject(new HashMap<>()); break; case "java.util.List" : jsonGenerator.writeObject(new ArrayList<>()); break; case "java.util.Date" : jsonGenerator.writeObject(""); break; default: log.info("当前属性:[{}]的类型:[{}]没匹配逻辑,返回原值", filedType.getName(),currentFeildName); jsonGenerator.writeObject(value); } } else { System.out.println("没有匹配到实体类-------" + currentFeildName); jsonGenerator.writeObject(value); } } }); return objectMapper; } }
测试类如下:
package com.example.demo.entity; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** * @author 帝眼未来-帮回家 * 牛逼的jackson能做到让我们惊讶的事情测试类 */ @Data public class TestResponse { private String name; private String fullName; @JsonProperty("Addr") private String addr; private Integer age; private List<String> allIds; private Map<String,Integer> paramMap; private Set<String> paramSet; private Boolean isExte; private Double aa; private Float bbb; private Date createDate; }
controller如下:
package com.example.demo.controller; import com.example.demo.entity.TestResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @author 帝眼未来-帮回家 * 测试Controller */ @Controller @RequestMapping(value = "/test") public class TestJsonDefaultController { @RequestMapping(value = "/getDealerLicense") @ResponseBody public TestResponse getDealerLicense(String name,String fullName) { TestResponse testResponse = new TestResponse(); testResponse.setName(name); testResponse.setFullName(fullName); testResponse.setAddr(null); return testResponse; } }
启动服务,访问该链接
http://localhost:8080/test/getDealerLicense?name=%E6%9D%8E%E5%9B%9B
返回结果如下:
{ "aa": 0, "Addr": "", "age": 0, "allIds": [], "bbb": 0, "createDate": "", "fullName": "", "isExte": true, "name": "李四", "paramMap": {}, "paramSet": [] }