来源 :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; } }