SpringBoot中使用Fastjson/Jackson對JSON序列化格式化輸出的若干問題


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM