一個(gè)SpringMVC接口能返回JSON又能返回XML? 安排!
我們有一個(gè)接口服務(wù)為下游的系統(tǒng)提供數(shù)據(jù)服務(wù),本來好好的大家都愉快地傳遞JSON,非常和諧??勺罱袀€(gè)新需求去對接一個(gè)很老的系統(tǒng),這倒是不算啥,可這個(gè)老系統(tǒng)數(shù)據(jù)不是以JSON傳遞的而是以XML傳遞的。
同事小王想了個(gè)餿主意,把原來的接口原版拷貝一遍統(tǒng)一把返回類型改成XML不就行了?嗯,接口路徑需要占用一套,權(quán)限配置多了一套,還要額外維護(hù)一套代碼,這主意太餿了。經(jīng)過大家的研究發(fā)現(xiàn)了Spring MVC的某個(gè)機(jī)制可以滿足需求。
原理
在HTTP協(xié)議里,當(dāng)客戶端發(fā)起一個(gè)HTTP請求時(shí),可以攜帶一個(gè)請求頭Accept來告訴服務(wù)端,客戶端可以接受哪些響應(yīng)類型(MIME),可以是一個(gè)也可以是多個(gè)?,F(xiàn)在前后端分離普遍使用這種:
- Accept:application/json
對于Spring MVC框架來說接受到對應(yīng)的Accept會根據(jù)一定的策略找到對應(yīng)的HttpMessageConverter來處理響應(yīng)數(shù)據(jù)的格式。因此我們只需要找到一個(gè)動(dòng)態(tài)指定Accept的方法就行了。
內(nèi)容協(xié)商
聽起來就很好理解,需要什么內(nèi)容大家協(xié)商,共同解決問題。Spring MVC提供了一種被稱作內(nèi)容協(xié)商的機(jī)制,客戶端在請求時(shí)聲明需要的MIME類型,服務(wù)端只需要配置一些策略就是實(shí)現(xiàn)一個(gè)接口返回不同MIME類型的數(shù)據(jù)格式,想要JSON返回JSON,想要XML返回XML。
Spring MVC版本基于Spring MVC 5.3.9。
服務(wù)端配置內(nèi)容協(xié)商
內(nèi)容協(xié)商的配置由Spring MVC中的ContentNegotiationManager負(fù)責(zé),我們可以通過ContentNegotiationConfigurer配置它。
首先要在Spring MVC項(xiàng)目中加入Jackson的XML處理庫:
- <dependency>
- <groupId>com.fasterxml.jackson.dataformat</groupId>
- <artifactId>jackson-dataformat-xml</artifactId>
- </dependency>
然后配置WebMvcConfigurer中的內(nèi)容協(xié)商配置:
- @Configuration
- public class WebConfig implements WebMvcConfigurer {
- @Override
- public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
- configurer.favorParameter(true)
- // 客戶端請求url需要攜帶一個(gè)query參數(shù) 默認(rèn)名稱是 format
- .parameterName("format")
- // 如果不聲明 該query參數(shù) 返回的是json 如果你想指定默認(rèn)返回類型就需要聲明
- // .defaultContentType(MediaType.APPLICATION_XML)
- .mediaType("xml", MediaType.APPLICATION_XML)
- .mediaType("json", MediaType.APPLICATION_JSON);
- }
- }
這樣聲明以后客戶端請求接口中要攜帶一個(gè)query參數(shù)(參數(shù)名稱默認(rèn)為format,你可以修改它)來指定MIME的代號。根據(jù)上面的配置,如果你需要返回JSON:
- https://yourapi?format=json
你也可以不攜帶format參數(shù),因?yàn)槟J(rèn)就是JSON,修改默認(rèn)的MIME類型需要調(diào)用defaultContentType。
如果你需要返回XML:
- https://yourapi?format=xml
服務(wù)端的接口也需要簡單的改造:
- @GetMapping(value = "/get",produces = {"application/json","application/xml"})
- public Map<String, String> doGet(@RequestParam String foo, String bar) {
- Map<String, String> map = new HashMap<>();
- map.put("foo", foo);
- map.put("bar", bar);
- return map;
- }
需要根據(jù)配置在@RequestMapping或其簡化注解中聲明對應(yīng)的produce,這一點(diǎn)非常重要。這樣我們改動(dòng)的地方就非常的少了,能夠適應(yīng)更多的場景,而且維護(hù)起來也很簡單。
其它策略
其實(shí)Spring MVC的內(nèi)容協(xié)商還可以通過后綴擴(kuò)展名實(shí)現(xiàn),比如/yourapi.json或者/yourapi.xml。還有直接在客戶端請求頭中聲明MIME類型。這些都不太方便操作所以就不介紹了,有興趣可以去看官方文檔。
本文轉(zhuǎn)載自微信公眾號「碼農(nóng)小胖哥」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼農(nóng)小胖哥公眾號。