Spring的RestTemplata使用詳解
spring-web的RestTemplata是對java底層http的封裝,使用RestTemplata使用者可以不再關注底層的串連建立,並且RestTemplata不僅支援Rest規範,還可以定義傳回值物件類型。
在使用中可以直接new一個RestTemplate對象,在我們建立的RestTemplate對象中會有一些返回訊息的訊息轉換器,可以根據返回資料的MediaType尋找對應的轉換器並進行MediaType轉換。自己也可以建立訊息轉換器,建立一個類繼承AbstractGenericHttpMessageConverter<T>類或者實現HttpMessageConverter<T>介面,需要注意的是canRead方法和canWrite方法最好自己做判斷,在writeInternal或write方法中將參數寫入到流,在readInternal或read方法中將返回結果從流的body中擷取並進行類型映射。
RestTemplate對象在底層通過使用java.net包下的實現建立HTTP 要求,可以通過使用ClientHttpRequestFactory指定不同的HTTP請求方式。
ClientHttpRequestFactory介面主要提供了兩種實現方式:
- 一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)建立底層的Http請求串連。
- 一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient訪問遠端Http服務,使用HttpClient可以配置串連池和認證等資訊。
RestTemplate預設是使用SimpleClientHttpRequestFactory,內部是調用jdk的HttpConnection,預設逾時為-1,我們可以自己定義逾時時間
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();//設定連線逾時,單位毫秒factory.setConnectTimeout(5000);//設定讀取逾時,單位毫秒factory.setReadTimeout(10000);RestTemplate restTemplate = new RestTemplate(factory);
使用GET請求:
String url = "http://localhost:80/mandy/login.json?account=123456&password=123456"; Result res = restTemplate.getForObject(url, Result.class);
RestTemplate源碼:
@Override public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables); }
使用get請求直接將參數拼接到地址上最好,不知道什麼原因如果使用第三個參數,即便是MultiValueMap類型也不行(網上有人說用MultiValueMap類型可以,我試了不行)
使用POST請求:
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("name", "測試");
map.put("account", "qwer");
map.put("password", "qwer");
ObjectMapper mapper = new ObjectMapper();
String jsonStr = null;
try {
jsonStr = mapper.writeValueAsString(map);
} catch (Exception e) {
e.printStackTrace();
}
//建立HTTP頭部實體,填充頭部資訊,比如資料格式
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
//建立HTTP實體,可以直接利用構造方法將請求體和要求標頭放進去
HttpEntity<String> httpEntity = new HttpEntity<String>(jsonStr2, httpHeaders);
String url = "http://localhost:80/mandy/user_enable.json";
//調用方法進行請求
Result res2 = restTemplate.postForObject(url, httpEntity, Result.class);
RestTemplate源碼:
@Override public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request, responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables); }
使用PUT請求:
HashMap<String, Object> map = new HashMap<String, Object>();map.put("user_id", "1");map.put("enable", 0);
ObjectMapper mapper = new ObjectMapper();String jsonStr = null;try { jsonStr = mapper.writeValueAsString(map);} catch (JsonProcessingException e) { e.printStackTrace();}
//建立HTTP頭部實體,填充頭部資訊,比如資料格式HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
//建立HTTP實體,可以直接利用構造方法將請求體和要求標頭放進去HttpEntity<String> httpEntity = new HttpEntity<String>(jsonStr, httpHeaders); String url = "http://localhost:80/mandy/user_enable.json";restTemplate.put(url , httpEntity);
RestTemplate源碼:
@Override public void put(String url, Object request, Object... urlVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(request); execute(url, HttpMethod.PUT, requestCallback, null, urlVariables); }
這個方法有個小的缺點就是沒有請求結果的傳回值,如果需要用到傳回值,就不能用這個方法。
如果要使用delete類型的請求,RestTemplate的put方法的參數列中只有下面幾種
@Overridepublic void delete(String url, Object... urlVariables) throws RestClientException { execute(url, HttpMethod.DELETE, null, null, urlVariables);}@Overridepublic void delete(String url, Map<String, ?> urlVariables) throws RestClientException { execute(url, HttpMethod.DELETE, null, null, urlVariables);}@Overridepublic void delete(URI url) throws RestClientException { execute(url, HttpMethod.DELETE, null, null);}
這些方法並沒有給我們參數讓我們放請求體內容,所以如果要直接使用RestTemplate提供的Delete方法,介面必須使用restful風格,將參數放在地址中,通過@PathVariable(value="")註解將參數擷取到。
重點:其實我們可以直接使用RestTemplate的exchange方法,如
@Overridepublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, method, requestCallback, responseExtractor, uriVariables);}
這裡只列舉了一個方法,其他的可以看源碼,這個方法可以進行所有類型的請求。
在這個方法中,method參數可以通過HTTPMethod枚舉來進行擷取,requestEntity參數是自己封裝的HttpEntity實體,包含請求體和要求標頭,responseType參數是返回結果的映射類,uriVariables這個參數給我的印象就是雞肋(個人看法),擷取請求返回介面可以通過方法傳回值的getBody()方法擷取。