今天使用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>