來源 :https://my.oschina.net/Adven/blog/3036567
使用springboot-web編寫rest接口,接口需要返回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 { /** * 格式化輸出配置 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter<?> converter : converters) { if (converter instanceof MappingJackson2HttpMessageConverter) { MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter) converter; jacksonConverter.setPrettyPrint( true ); // 實際使用生效 } } } }
2.Fastjson方式
2.1引入fastjson,排除jackson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<!--排除jackson-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--,排除jackson(根據實際情況,下面的非必須)-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>com.fasterxml.jackson.core</groupId>-->
<!--<artifactId>jackson-databind</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
<scope>compile</scope>
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>com.fasterxml.jackson.core</groupId>-->
<!--<artifactId>jackson-databind</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
</dependency>
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<MediaType> 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<HttpMessageConverter<?>> converters) { Iterator<HttpMessageConverter<?>> 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<MediaType> 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; } }
