Spring RestTemplate中常見的請求方式
1.基本概念
Spring RestTemplate 是 Spring 提供的用於訪問 Rest 服務的客戶端,RestTemplate 提供了多種便捷訪問遠端Http服務的方法,能夠大大提高客戶端的編寫效率,所以很多客戶端比如 Android或者第三方服務商都是使用 RestTemplate 請求 restful 服務
藉助 RestTemplate,Spring應用能夠方便地使用REST資源 .Spring的 RestTemplate訪問使用了模版方法的設計模式.
2.Spring 中如何使用Rest資源
RestTemplate中定義了11個獨立的方法,分別是:
- delete() :在特定的URL上對資源執行HTTP DELETE操作
- getForEntity() :傳送一個HTTP GET請求,返回的ResponseEntity包含了響應體所對映成的物件
- getForObject() :傳送一個HTTP GET請求,返回的請求體將對映為一個自定義物件
- postForEntity() :POST 資料到一個URL,返回包含一個物件的ResponseEntity,這個物件是從響應體中對映得到的
- postForObject(): POST 資料到一個URL,返回根據響應體匹配形成的物件
- headForHeaders(): 傳送HTTP HEAD請求,返回包含特定資源URL的HTTP頭
- optionsForAllow() :傳送HTTP OPTIONS請求,返回對特定URL的Allow頭資訊
- postForLocation(): POST 資料到一個URL,返回新建立資源的URL
- put() :PUT 資源到特定的URL
- execute() :在URL上執行特定的HTTP方法,返回一個從響應體對映得到的物件
- exchange() :在URL上執行特定的HTTP方法,返回包含物件的ResponseEntity,這個物件是從響應體中對映得到的
其中前十個方法分別有三個過載形式,以getForObject為例:第一個引數是介面的url,第二個引數是接收的返回值的型別,第三個是你要傳的引數,可以為多個Object物件,也可以是一個Map .而返回型別則是傳入第二個引數對應的型別.
<T> T getForObject(String var1, Class<T> var2, Object... var3) throws RestClientException;
<T> T getForObject(String var1, Class<T> var2, Map<String, ?> var3) throws RestClientException;
<T> T getForObject(URI var1, Class<T> var2) throws RestClientException;
而最後一個exchange方法有8個過載形式,你可以自由的組裝REST呼叫方法,而返回的結果都是響應體所對映成的物件-ResponseEntity:
<T> ResponseEntity<T> exchange(String var1, HttpMethod var2, HttpEntity<?> var3, Class<T> var4, Object... var5) throws RestClientException;
<T> ResponseEntity<T> exchange(String var1, HttpMethod var2, HttpEntity<?> var3, Class<T> var4, Map<String, ?> var5) throws RestClientException;
<T> ResponseEntity<T> exchange(URI var1, HttpMethod var2, HttpEntity<?> var3, Class<T> var4) throws RestClientException;
<T> ResponseEntity<T> exchange(String var1, HttpMethod var2, HttpEntity<?> var3, ParameterizedTypeReference<T> var4, Object... var5) throws RestClientException;
<T> ResponseEntity<T> exchange(String var1, HttpMethod var2, HttpEntity<?> var3, ParameterizedTypeReference<T> var4, Map<String, ?> var5) throws RestClientException;
<T> ResponseEntity<T> exchange(URI var1, HttpMethod var2, HttpEntity<?> var3, ParameterizedTypeReference<T> var4) throws RestClientException;
<T> ResponseEntity<T> exchange(RequestEntity<?> var1, Class<T> var2) throws RestClientException;
<T> ResponseEntity<T> exchange(RequestEntity<?> var1, ParameterizedTypeReference<T> var2) throws RestClientException;
其中ResponseEntity物件繼承於HttpEntity ,在HttpEntity的基礎上又封裝了一個HttpStatus屬性 .
這樣如果返回ResponseEntity物件的話,我們可以拿到所有的關於請求的資訊,包括了 請求頭,請求狀態 ,和請求體的資訊.如:
例項:
介面提供方:
介面呼叫 :
@Service
@Transactional
public class XXXServiceImpl implements XXXService{
@Autowired
private XXXMapper mapper;
@Autowired
private RestTemplate restTemplate;
private final static Logger logger = LoggerFactory.getLogger(XXXServiceImpl.class);
@Value(value = "${esb.product.url}")
private String url;
@Value(value = "${esb.product.username}")
private String username;
@Value(value = "${esb.product.password}")
private String password;
/**
* @Author younus
* @Description // 呼叫介面
* @Param
**/
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void getEsbProductMultiples() {
HttpHeaders headers = createHeaders(username, password);
HttpEntity requestWithBasicAuth = new HttpEntity(headers);
//介面返回的資料
EsbProductMultiple datas= restTemplate.postForObject(url, requestWithBasicAuth, EsbProductMultiple.class);
List<PubProductMutiple> pubProductMutiples=datas.getProductMutiples();
if (pubProductMutiples != null && !pubProductMutiples.isEmpty()&& "S".equals(datas.getRetStatus())){
//生成批次號
String uuid= UUID.randomUUID().toString().replaceAll("-","");
//具體業務邏輯
}
logger.info("-----------------------介面呼叫完成------------------------");
}
}
//模擬頭資訊
private HttpHeaders createHeaders(String username, String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
set( "Authorization", authHeader );
}};
}
}
可以看到呼叫postForObject()會將結果封裝為我們自定義的物件.
excute方法
所有的get、post、delete、put、options、head、exchange方法最終呼叫的都是excute()方法,excute()方法只是將String格式的URI轉成了java.net.URI,之後呼叫了doExecute方法。舉個栗子:
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException {
RequestCallback requestCallback = this.acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)this.execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
}
呼叫過程:
execute方法:
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Object... urlVariables) throws RestClientException {
URI expanded = this.getUriTemplateHandler().expand(url, urlVariables);
return this.doExecute(expanded, method, requestCallback, responseExtractor);
}