zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    SSH框架中使用注解和xml配置的区别
    web项目中log4j的配置
    嵌入式—ASCII码
    MATLAB
    MATLAB
    MATLAB
    MATLAB
    CentOS 7将网卡名称eno16777736改为eth0
    图像增强处理
    Debussy与modelsim联仿时 do 文件脚本
  • 原文地址:https://www.cnblogs.com/niunafei/p/11678921.html
Copyright © 2011-2022 走看看