SpringBoot中使用Fastjson/Jackson对JSON序列化格式化输出的若干问题
Use-Fastjson-and-Jackson-to-Serialized-and-Formated-Output-of-JSON-in-SpringBoot
之前使用springboot-web编写rest接口,接口需要返回json数据,自己是个强迫症患者,看着默认输出的json字符串挤在一起,看着就难受,所以总想着把输出的json数据经过格式化处理后再输出。 目前国内比较常用的fastjson使用比较方便,但是SpringBoot默认使用的Jackson,替换的时候有时候因为其他组件也使用到了jackson,所以无法100%成功替换。 不喜欢使用jackson主要是jackson对格式化输出支持不太友好,自己使用的时候遇到许多坑,至今也没把坑填好,所以一直就不待见它,有时候又不得不用。 下面总结一下Fastjson/Jackson两种对json序列化+格式化输出的配置总结。
1.Jackson方式(SpringBoot中的默认方式):
1.1application.yml配置文件
spring:
jackson:
#日期格式化
date-format: yyyy-MM-dd HH:mm:ss
serialization:
#格式化输出
indent_output: true
- 网上提供的方案,可是实际配置并不能生效
1.2使用JavaConfig文件配置Jackson格式化输出
@Configuration
public class JacksonConfig extends WebMvcConfigurationSupport {
// 注释部分配置无效
// @Bean
// @Primary
// @ConditionalOnMissingBean(ObjectMapper.class)
// public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
// ObjectMapper objectMapper = builder.createXmlMapper( false ).build();
//
// // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// // Include.Include.ALWAYS 默认
// // Include.NON_DEFAULT 属性为默认值不序列化
// // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// // Include.NON_NULL 属性为NULL 不序列化
// // objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
// objectMapper.setSerializationInclusion( JsonInclude.Include.ALWAYS );
// objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
// // 允许出现特殊字符和转义符
// objectMapper.configure( JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true );
// // 允许出现单引号
// objectMapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
// // 字段保留,将null值转为""
// objectMapper.getSerializerProvider().setNullValueSerializer( new JsonSerializer
2.Fastjson方式
2.1引入fastjson,排除jackson
com.alibaba
fastjson
1.2.56
org.springframework.boot
spring-boot-starter-web
com.fasterxml.jackson.core
jackson-databind
org.springframework.security.oauth
spring-security-oauth2
2.3.4.RELEASE
org.springframework.security.oauth.boot
spring-security-oauth2-autoconfigure
${spring-boot.version}
compile
2.2 使用JavaConfig配置
- SpringBoot中fastjson的配置有两种方式:
2.2.1 方式一
配置Bean 使用fastjson的方式实现HttpMessageConverters
@Configuration
public class FastJSONConfig {
/**
* Fastjson
*
* @return
*/
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
List mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
fastJsonConfig.setSerializerFeatures(
SerializerFeature.DisableCircularReferenceDetect, //禁用循环引用
SerializerFeature.PrettyFormat,
SerializerFeature.IgnoreNonFieldGetter
);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter> converter = fastJsonHttpMessageConverter;
return new HttpMessageConverters(converter);
}
}
2.2.2方式二
- Spring5.x中实现WebMvcConfigurer接口,并重写configureMessageConverters方法,向其中添加FastJsonHttpMessageConverter
@Configuration
public class FastJsonHttpConverterConfig implements WebMvcConfigurer {
// fastjson配置
@Override
public void configureMessageConverters(List> converters) {
Iterator> iterator = converters.iterator();
while(iterator.hasNext()){
HttpMessageConverter> converter = iterator.next();
if(converter instanceof MappingJackson2HttpMessageConverter){
iterator.remove();
}
}
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty, // List类型字段为null时输出[]而非null
SerializerFeature.WriteMapNullValue, // 显示空字段
SerializerFeature.WriteNullStringAsEmpty, // 字符串类型字段为null时间输出""而非null
SerializerFeature.WriteNullBooleanAsFalse, // Boolean类型字段为null时输出false而null
SerializerFeature.PrettyFormat, // 美化json输出,否则会作为整行输出
SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而非null
SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而非null
SerializerFeature.WriteDateUseDateFormat, // 时间格式yyyy-MM-dd HH: mm: ss
SerializerFeature.DisableCircularReferenceDetect); // 禁用循环引用检测
converter.setFastJsonConfig(config);
converters.add(converter);
List supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
supportedMediaTypes.add(MediaType.APPLICATION_PDF);
supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
supportedMediaTypes.add(MediaType.IMAGE_GIF);
supportedMediaTypes.add(MediaType.IMAGE_JPEG);
supportedMediaTypes.add(MediaType.IMAGE_PNG);
supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.TEXT_XML);
converter.setSupportedMediaTypes(supportedMediaTypes);
}
}
2.2.3 总结
- fastjson替换jackson并不能保证100%成功,但是都能最终实现格式化输出。HttpMessageConverter的具体实现需要深入阅读源码,从源码上进一步寻找答案。
- 使用fastjson替换在自己DIY的OAuth2-SSO项目中认证服务器无法成功替换,最后基于1中jackson最终实现格式化输出。
3.附Restful接口输出json数据
@RestController
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
/**
* 资源服务器提供的受保护接口
* @param authentication
* @return
*/
@GetMapping(value = "/user",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Authentication getUserInfo(Authentication authentication) {
logger.info("authentication resource: user {}", authentication);
System.out.println(JSON.toJSONString(authentication, SerializerFeature.PrettyFormat));
return authentication;
}
/**
* 提供一个/user/me接口供客户端来获得用户的凭证
* @param principal
* @return
*/
@GetMapping(value = "/user/me",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Principal getUserPrincipal(Principal principal) {
System.out.println("com.acanx.sso.oauthserver.controller.UserController#user Principal:"+principal);
logger.info("Principal: user {}", principal);
System.out.println(JSON.toJSONString(principal, SerializerFeature.PrettyFormat));
return principal;
}
}
参考
- Spring Boot Actuator pretty print JSON
- 解决Springboot 2.x 配置FastJson不生效问题
- Spring-boot替换框架json为fastjson
- SpringBoot2.0使用FastJson转换器(以及MessageConverter的一些问题)
- SpringBoot 消息转换器 HttpMessageConverter
- spring boot2 配置 FastJsonHttpMessageConverter 不起作用
- SpringBoot 2.0整合jackson配置日期格式化和反序列化