- 当请求接口不返回数据时,封装后响应体传递的 JSON 数据中 data 的值就会显示为 null,整体上看起来并不协调,我们可以对 data 的空值进行处理,转化为空符串
- 我们可以自定义一个 Jackson 配置类,在配置类中使用 Jackson2ObjectMapperBuilder 来建一个 ObjectMapper 用于获取当前 ObjectMapper实例的序列化对象,然后将序列化时为 null 值实例化一个新的 JsonSerializer 类用于写入为空字符串
示例
@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 o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(""); } }); return objectMapper; } } |
类型空处理
- 虽然将 null 值显示为空字符串协调了响应体,但是仍然没解决数据应该根据类型显示的问题。正常情况下,我们应该能够根据 JSON 中的数据格式大致判断出属性的数据类型,而不是统一处理为空字符。
类型 |
默认返回值 |
String |
"" |
Boolean |
false |
Integer Float Double BigDecimal Long Short |
0 |
Array List Set |
[] |
Date |
null |
- 我们可以前面的基础上,在JsonSerializer.serialize 方法中通过反射获取数据类型,根据数据类型再对特定数据类型的处理
示例
@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 o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { String fieldName = jsonGenerator.getOutputContext().getCurrentName(); //反射获取字段 Class<?> currentClass = jsonGenerator.getCurrentValue().getClass(); Field field = ReflectionUtils.findField(currentClass, fieldName); System.out.println(field.getType()); //判断空值 if (ObjectUtils.isNull(field)) { return; } //String类型返回"" if (Objects.equals(field.getType(), String.class)) { jsonGenerator.writeString(""); return; } //Boolean类型返回false if (Objects.equals(field.getType(), Boolean.class)) { jsonGenerator.writeBoolean(false); return; } // 数字类型Integer、Float、Double、BigDecimal、Long、Short等类型返回0 if (Number.class.isAssignableFrom(field.getType())) { jsonGenerator.writeNumber(0); return; } //Array、List、Set类型返回[] if (field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())) { jsonGenerator.writeStartArray(); jsonGenerator.writeEndArray(); return; } //Date类型返回null if (Date.class.isAssignableFrom(field.getType()) || LocalDateTime.class.isAssignableFrom(field.getType()) || LocalDate.class.isAssignableFrom(field.getType()) || LocalTime.class.isAssignableFrom(field.getType())) { jsonGenerator.writeNull(); return; }
//其他Object返回{} jsonGenerator.writeStartObject(); jsonGenerator.writeEndObject(); } }); return objectMapper; } } |
空值屏蔽
- 当业务逻辑和异常处理足够完整时,我们还可以直接排除对 data 为 null 情况下的序列化显示
- 对空值取消序列化在 SpringBoot 中有两种方法
- 使用注解(@JsonInclude)
- Jackson 全局配置(spring.jackson.default-property-inclusion)
- @JsonInclude 是一个 Jackson 库的注解,用于指定在序列化 Java 对象为 JSON 格式时应包含哪些属性。我们可以通过设置 JsonInclude.Include.NON_NULL 排除对空值的序列化
示例
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> { private int code; private T data; private String msg;
public Result(T data) { this.code = ResultCode.SUCCESS.getCode(); this.data = data; this.msg = ResultCode.SUCCESS.getMsg(); }
public Result(ResultCode resultCode, T data) { this.code = resultCode.getCode(); this.data = data; this.msg = resultCode.getMsg(); }
public static <T> Result<T> success(T data) { return new Result<>(ResultCode.SUCCESS, data); } } |
- 在 Jackson 配置中允许自定义包含的参数类型,我们只需要在 application.xml 全局配置中设置 spring.jackson.default-property-inclusion 的参数值为 non_null ,这种方法会作用到全局,因此并不推荐使用
示例
spring.jackson.default-property-inclusion: non_null
注
空值排除建议在数据处理相对完整的情况下使用,否则在返回数据为空时会缺少 data 属性,降低数据判断的准确性