SpringBoot 定制化返回数据的实现示例
此时我们的返回结构如下:
{ "code":200, "msg":"ok", "data":{ "id":1, "username":"steve", "secretKey":"xxx", "expiredAt":null, "createdAt":"2020-07-07T06:09:15" } }
但上面有几个问题:
- 我希望字段是以下划线命名方式,也就是createdAt改成created_at这样
- 我希望某些字段值的输出格式可以自定义,比如日期类型我希望输出是yyyy-MM-ddHH:mm:ss
- 我不希望secretKey这类具有安全性质的字段返回给调用方
- 我不希望有null这样的输出,避免给调用方不必要的麻烦
定制字段名
我们有两种选择,第一种是在每一个字段上通过添加@JsonProperty注解来实现,如下:
@JsonProperty("secret_key") privateStringsecretKey;
这种方式灵活度高,缺点就是繁琐,变量名是单个单词的不用转换,多个单词的如果要保持统一格式就需要每个都写上,工作量不小。
第二种方式就是全局配置Spring内置的Jackson的序列化转换器,在config目录下新建JsonConfig.java文件:
packagecom.foxescap.wxbox.config; importcom.fasterxml.jackson.databind.PropertyNamingStrategy; importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.http.converter.HttpMessageConverter; importorg.springframework.http.converter.json.Jackson2ObjectMapperBuilder; importorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter; importorg.springframework.web.servlet.config.annotation.EnableWebMvc; importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer; importjava.time.format.DateTimeFormatter; importjava.util.List; /** *@authorxfly */ @EnableWebMvc @Configuration publicclassWebMvcConfigimplementsWebMvcConfigurer{ @Bean publicLocalDateTimeSerializerlocalDateTimeSerializer(){ returnnewLocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss")); } @Override publicvoidconfigureMessageConverters(List>converters){ converters.add( newMappingJackson2HttpMessageConverter( newJackson2ObjectMapperBuilder() .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .build() ) ); } }
我们通过重写WebMvcConfigurer接口的configureMessageConverters方法,添加自定义的JSON转换器,关键是propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)这行代码,设置属性的命名策略为下划线命名方式。
定制字段值格式
最常见的就是对时间类型的字段格式化,也有两种方式,第一种是在每个字段上添加@JsonFormat注解,比如格式化日期时间:
@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss") privateLocalDateTimeexpiredAt;
也可以全局配置,我们在上面JsonConfig代码的基础上,加上一个类型串行器:
@Bean publicLocalDateTimeSerializerlocalDateTimeSerializer(){ returnnewLocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss")); } @Override publicvoidconfigureMessageConverters(List>converters){ converters.add( newMappingJackson2HttpMessageConverter( newJackson2ObjectMapperBuilder() .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .serializerByType(LocalDateTime.class,localDateTimeSerializer()) .build() ) ); }
这样就能对全局LocalDateTime类型的字段序列化时转换成我们自定义的格式了。
定制可见性
当我们不需要有字段被序列化,即需要忽略它,那么可以在那个字段上添加@JsonIgnore注解即可。
处理Null
一般地,要么是直接忽略值为null的字段,要么是将null转换成空字符串处理,前者可以直接在每个需要的字段上加@JsonInclude(Include.NON_NULL)注解,或者也可以在每个需要序列化的类上加,当然也可以全局配置,在.build()前加入.serializationInclusion(JsonInclude.Include.NON_NULL)即可。
如果我们不希望null值直接被忽略,又不需要直接给调用方返回null,那么可以添加一个setNullValueSerializer方法自定义输出:
@Override publicvoidconfigureMessageConverters(List>converters){ varbuilder=newJackson2ObjectMapperBuilder() .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) //.serializationInclusion(JsonInclude.Include.NON_NULL) .serializerByType(LocalDateTime.class,localDateTimeSerializer()) .build(); builder.getSerializerProvider() .setNullValueSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objecto,JsonGeneratorjsonGenerator,SerializerProviderserializerProvider)throwsIOException{ jsonGenerator.writeString(""); } }); converters.add(newMappingJackson2HttpMessageConverter(builder)); }
纠结过是直接不序列化Null值还是设为空值,考虑到对于调用方,如果直接将Null值忽略了的话,数据的结构完整性就大大破坏了,比如一个数组,有几个数组元素里的字段有,有几个没有,对于调用方就非常不友好了。
如果你想对不同变量类型的Null值分别处理的话,那么就需要重写changeProperties方法,比如对于数组集合类型的字段,如果是Null值则序列化成[];如果是字符串类型的字段,序列化成"";如果是不二类型的字段,序列化成false等等:
@Override publicvoidconfigureMessageConverters(List>converters){ varbuilder=newJackson2ObjectMapperBuilder() .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .serializerByType(LocalDateTime.class,localDateTimeSerializer()) .build(); builder.setSerializerFactory(builder.getSerializerFactory().withSerializerModifier(newBeanSerializerModifier(){ @Override publicList changeProperties(SerializationConfigconfig,BeanDescriptionbeanDesc,List beanProperties){ for(varbeanPropertyWriter:beanProperties){ varjavaType=beanPropertyWriter.getType(); if(javaType.isArrayType()||javaType.isCollectionLikeType()){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objecto,JsonGeneratorjsonGenerator,SerializerProviderserializerProvider)throwsIOException{ jsonGenerator.writeStartArray(); jsonGenerator.writeEndArray(); } }); }elseif(javaType.isTypeOrSubTypeOf(String.class)){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{ gen.writeString(""); } }); }elseif(javaType.isTypeOrSuperTypeOf(Boolean.class)){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{ gen.writeBoolean(false); } }); }elseif(javaType.isMapLikeType()){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{ gen.writeStartObject(); gen.writeEndObject(); } }); }elseif(javaType.isTypeOrSuperTypeOf(Integer.class)|| javaType.isTypeOrSuperTypeOf(Long.class)|| javaType.isTypeOrSuperTypeOf(Double.class)|| javaType.isTypeOrSuperTypeOf(Float.class)){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{ gen.writeNumber(0); } }); }elseif(javaType.isTypeOrSuperTypeOf(LocalDateTime.class)|| javaType.isTypeOrSuperTypeOf(LocalDate.class)){ beanPropertyWriter.assignNullSerializer(newJsonSerializer<>(){ @Override publicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{ gen.writeString(""); } }); } } returnbeanProperties; } })); converters.add(newMappingJackson2HttpMessageConverter(builder)); }
到此这篇关于SpringBoot定制化返回数据的实现示例的文章就介绍到这了,更多相关SpringBoot定制化返回数据内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!