? ? ? ? ? ? ?最近在spring boot項(xiàng)目中REST接口的開發(fā)中使用restTemplate踩了一些坑堰汉,其實(shí)是自己對(duì)提交的各種方式有點(diǎn)混淆进栽,現(xiàn)在梳理出來供大家使用避免再次踩坑中狂。
? ? ? ? ? ? ?利用RestTemplate進(jìn)行接口測(cè)試是種常見的方法丁溅,但在使用過程中,由于其方法參數(shù)眾多义锥,很多同學(xué)又混淆了表單提交與Payload提交方式的差別柳沙,而且接口設(shè)計(jì)與傳統(tǒng)的瀏覽器使用的提交方式又有差異,經(jīng)常出現(xiàn)各種各樣的錯(cuò)誤拌倍,如405錯(cuò)誤赂鲤,或者根本就得不到提交的數(shù)據(jù)。
1. 用exchange方法提交
exchange既可以執(zhí)行POST方法贰拿,還可以執(zhí)行GET蛤袒,所以應(yīng)用最為廣泛,使用方法如下:
? ? ? String url ="http://localhost/mirana-ee/app/login";
? ? ? RestTemplate client =newRestTemplate();
? ? ? HttpHeaders headers =newHttpHeaders();//? 請(qǐng)勿輕易改變此提交方式膨更,大部分的情況下妙真,提交方式都是表單提交 ? ? ? ? headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);//? 封裝參數(shù),千萬(wàn)不要替換為Map與HashMap荚守,否則參數(shù)無法傳遞
? ? ?MultiValueMap params=newLinkedMultiValueMap();//? 也支持中文params.add("username","用戶名");
? ? ? params.add("password","123456");
? ? ?HttpEntity> requestEntity =newHttpEntity>(params, headers);//? 執(zhí)行HTTP請(qǐng)求
? ? ? ResponseEntity response = client.exchange(url, HttpMethod.POST, requestEntity, String.class);//? 輸出結(jié)果
? ? ? System.out.println(response.getBody());
2珍德、用postForEntity進(jìn)行提交
postForEntity是對(duì)exchange的簡(jiǎn)化练般,僅僅只需要減少HttpMethod.POST參數(shù),如下:
//? 上面的代碼完全一樣//? 僅需替換exchange方法
ResponseEntity response = client.postForEntity(url, requestEntity , String.class );
3. 關(guān)于表單提交與Payload提交的差異
在Controller的方法參數(shù)中锈候,如果將“@ModelAttribute”改為“@RequestBody”注解薄料,則此時(shí)的提交方式為Payload方式提交,詳細(xì)的差異請(qǐng)參見《 $.ajax使用總結(jié)(一):Form提交與Payload提交》泵琳,代碼示例如下:
//? 請(qǐng)注意@RequestBody注解
? ? @RequestMapping(value="/login", method=RequestMethod.POST, consumes="application/json")
? ? ? //? 千萬(wàn)不要畫蛇添足添加@ModelAttribute摄职,否則會(huì)被其覆蓋,如下
? ? ? ? //? public Account getAccount(@RequestBody@ModelAttribute Accountccount)
? ? ? ? ? ? ?publicAccountgetAccount(@RequestBody Account account) {? ?
? ? ? ? ? ? ? ? ? ? ? ? ? account.setVersion(newDate());
? ? ? ? ? ? ? ? ? ? ? ? ? ?return ? account;
? ? ? ? ? ? ? }
再次強(qiáng)調(diào)一次获列,千萬(wàn)不要畫蛇添足再次添加“@ModelAttribute”谷市,因?yàn)槠鋬?yōu)先級(jí)比較高,所以系統(tǒng)會(huì)采用表單方式解析提交內(nèi)容击孩。
對(duì)于Payload方式迫悠,提交的內(nèi)容一定要是String,且Header要設(shè)置為“application/json”巩梢,示例如下:
? ? ? //? 請(qǐng)求地址
? ? ?String url ="http://localhost/mirana-ee/app/login";RestTemplate client =newRestTemplate();
? ? ?//? 一定要設(shè)置header?
? ? ?HttpHeaders headers =newHttpHeaders();
? ? ?headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
? ? ?//? 將提交的數(shù)據(jù)轉(zhuǎn)換為String
? ? ?//? 最好通過bean注入的方式獲取ObjectMapper
? ? ?ObjectMapper mapper =newObjectMapper();
? ? ?Map params= Maps.newHashMap();
? ? ? params.put("username","國(guó)米");
? ? ? params.put("password","123456");
? ? ? ?String value = mapper.writeValueAsString(params);
? ? ? ?HttpEntity requestEntity =newHttpEntity(value, headers);
? ? ? ?//? 執(zhí)行HTTP請(qǐng)求
? ? ? ?ResponseEntity response = client.postForEntity(url, requestEntity , String.class );
? ? ? ?System.out.println(response.getBody());
如果內(nèi)容不是以String方式提交创泄,那么一定會(huì)出現(xiàn)以下錯(cuò)誤:
Exceptioninthread"main"org.springframework.web.client.HttpClientErrorException:400Bad Request? ? at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)? ? at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)? ? at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)? ? at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)? ? at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:407)
最后需要強(qiáng)調(diào)的是,通過@RequestBody是無法獲取到請(qǐng)求參數(shù)括蝠,如將上面服務(wù)端的代碼改為如下格式鞠抑,則肯定得不到數(shù)據(jù),但表單提交則相反又跛。
結(jié)論
RestTemplate能大幅簡(jiǎn)化了提交表單數(shù)據(jù)的難度碍拆,并且附帶了自動(dòng)轉(zhuǎn)換JSON數(shù)據(jù)的功能若治,但只有理解了HttpEntity的組成結(jié)構(gòu)(header與body)慨蓝,且理解了與uriVariables之間的差異,才能真正掌握其用法端幼。