Spring Boot應用的Controller返回的集合類數據是XML格式的可能原因

  今天使用Eureka Client的時候發現Controller打了@RestController註解,對於返回值是集合類的API接口,其數據還是會被系列化成XML格式:

    @GetMapping("/user-instance")
    public List<ServiceInstance> showUserServiceInfo() {
        return this.discoveryClient.getInstances("provider-user-metadata");
    }

  結果:

<List>
    <item>
        <scheme>http</scheme>
        <host>192.168.0.102</host>
        <port>8000</port>
        <metadata>
            <author>xurm</author>
            <management.port>8000</management.port>
            <age>26</age>
        </metadata>
    </item>
</List>

  經過排查發現是spring-cloud-starter-netflix-eureka-client的Maven依賴間接引入了jackson-dataformat-xml包,而如果Spring的http消息轉換器(HttpMessageConverter)使用了該包會,那麼它會根據http請求頭上的Accept來決定返回XML還是JSON。然而目前大多數瀏覽器在沒有額外設置的情況下,默認的Accept值都是"text/html,application/xhtml+xml,application/xml",這就使得直接在瀏覽地址欄訪問接口時,預期要返回JSON的返回了XML,因爲JSON和XML格式是可以互轉的!

  但是如今應用開發使用JSON方便一些,特別是與前端數據交換的時候,可以直接用上JS與JSON的無縫對接優勢,所以得把返回值改成JSON纔行,方法有多種,這裏介紹兩種:

  第一種是:如果你的應用不會再需要返回xml的系列化格式,那麼直接在pom.xml文件中將jackson-dataformat-xml這外包排除即可(如果其他包也進行了jackson-dataformat-xml的依賴引用也要視情況排除):

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.3.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

  刷新maven,重新啓動應用,再次訪問相應接口:

[{
    "scheme": "http",
    "host": "192.168.0.102",
    "port": 8000,
    "secure": false,
    "metadata": {
        "author": "xurm",
        "management.port": "8000",
        "age": "26"
    }
}]

  第二種是:不排除jackson-dataformat-xml包,而是直接在相應接口方法上明確指定將返回JSON格式的值:

    @GetMapping(value = "/user-instance", produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE)
    public List<ServiceInstance> showUserServiceInfo() {
        return this.discoveryClient.getInstances("provider-user-metadata");
    }

 

  從上面的問題原理可知:項目裏一個接口是可以同時支持返回XML和JSON的,只要在Accept中聲明你要XML還是要JSON。當然也有藉助第三方包(jackson-jaxrs-xml-provider),然後通過URL後綴是*.json還是*.xml來返回JSON還是XML的做法!如果要讓接口同時支持返回XML和JSON,就不能再在接口方法上明確指定將返回什麼格式的值了

    @GetMapping(value = "/user-instance")
    public List<ServiceInstance> showUserServiceInfo() {
        return this.discoveryClient.getInstances("provider-user-metadata");
    }

 

  最後,其實還可以通過添加自定義的Spring的http消息轉換器(HttpMessageConverter)的方法來定製返回值的系列化,方法就是實現WebMvcConfigurer,並重寫configureMessageConverters方法,例如換用阿里的Fastjson來做http消息轉換:

    /**
     * 消息轉換器自定義配置,向當前的Http消息轉換器列表增加阿里雲的FastJson消息轉換器
     *
     * @param converters 當前的Http消息轉換器列表對象
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastJsonConverter.setFastJsonConfig(fastJsonConfig);
        //converters.add(fastJsonConverter);//這會讓fastJsonConverter排在消息轉換器管道列表的最後,可能會輪不到它處理消息轉換
        converters.add(0, fastJsonConverter);//要顯示指明將fastJsonConverter排在消息轉換器管道列表的首位
    }

  pom.xml中引入Fastjson的依賴:

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章