[英]Spring Boot http call to remote web service
我必須使用Spring Boot 2.0.5從我的 Web 應用程序構建中調用遠程 REST 端點
我可以使用 HttpURLConnection,但由於 Spring 有 RestTemplate,我檢查了它是什么,我發現它很快就會被棄用:
此頁面還提到了通過 HTTP 調用的新類。 可以以同步和異步方式使用它:
WebClient 提供了 RestTemplate 的現代替代方案,有效支持同步和異步以及流場景
問題是我在 WebClient 的 javadoc 中沒有看到任何關於同步工作方式的說明:
WebClient 的另一個問題 - 要使其正常工作,我需要在類路徑中使用 WebFlux https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-webclient.html
但這會破壞我的 Spring Security 配置,因為它以同步方式構建。 據我了解,一旦我有了 WebFlux Spring Security 將使用異步配置。
如何使用 Spring 對遠程端點進行 http 調用,還是應該避免並使用 HttpURLConnection 類(或 Apache 的庫)?
更新
WebFlux 似乎不會以同步方式對 Spring Security buit 造成任何問題。
另請注意,我的應用程序不是響應式的 - 它是多線程的(抱歉,如果我之前不清楚這一點)。 我有交易,所以反應式方法似乎不適合我的情況。
您可以使用 Spring org.springframework.web.client.AsyncRestTemplate 進行異步 Rest 調用。 下面是我用於同步和異步調用的實用程序之一。 下面是 Rest 實用程序和 CallBack for Async。
/**
*
*/
package com.debopam.services.policyenquiryservice.rest.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.AsyncRestTemplate;
/**
* @author dpoddar
*
*/
public class RestUtil {
private String url;
private HttpMethod httpMethod;
private MultiValueMap<String, String> headers;
private Map<String, Object> params;
private Class<?> responseType;
private List<Object> uriVariables;
private HttpEntity<Object> httpEntity;
//AsyncRestTemplate asyncRestTemplate = (AsyncRestTemplate) ContextProvider.getBean("customAsyncRestTemplate");
/**
* @param url
* @param httpMethod
* @param headers
* @param params
* @param responseType
* @param uriVariables
*/
public RestUtil(String url, HttpMethod httpMethod, MultiValueMap<String, String> headers,
Map<String, Object> params, Class<?> responseType, List<Object> uriVariables) {
super();
this.url = url;
this.httpMethod = httpMethod;
this.headers = headers;
this.params = params;
this.responseType = responseType;
this.uriVariables = uriVariables;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public Foo callServicesync(RestTemplate restTemplate) {
//DO a sync Call
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void callServiceAsync(AsyncRestTemplate asyncRestTemplate,ResponseCallBack responseCallBack) {
if(asyncRestTemplate.getMessageConverters().isEmpty()){
asyncRestTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
}
ListenableFuture restCall = null;
if(null != uriVariables){
restCall = asyncRestTemplate.exchange(this.url, this.httpMethod, this.httpEntity, responseType,uriVariables);
}else{
restCall = asyncRestTemplate.exchange(this.url, this.httpMethod, this.httpEntity, responseType);
}
restCall.addCallback(responseCallBack);
}
public static class RestUtilBuilder {
private String url;
private HttpMethod httpMethod;
private MultiValueMap<String, String> headers;
private Map<String, Object> params;
private Class<?> responseType;
private List<Object> uriVariables;
public RestUtilBuilder url(String url) {
this.url = url;
return this;
}
public RestUtilBuilder httpMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
return this;
}
public RestUtilBuilder headers(MultiValueMap<String, String> headers) {
this.headers = headers;
return this;
}
public RestUtilBuilder addHeader(String key,String value) {
if(null == this.headers){
this.headers = new LinkedMultiValueMap<>();
}
this.headers.add(key, value);
return this;
}
public RestUtilBuilder params(Map<String, Object> params) {
this.params = params;
return this;
}
public RestUtilBuilder addparam(String key,Object value) {
if(null == this.params){
this.params = new HashMap<>();
}
this.params.put(key, value);
return this;
}
public RestUtilBuilder responseType(Class<?> responseType) {
this.responseType = responseType;
return this;
}
public RestUtilBuilder uriVariables(List<Object> uriVariables) {
this.uriVariables = uriVariables;
return this;
}
public RestUtil build() {
RestUtil util = new RestUtil(url, httpMethod, headers, params, responseType, uriVariables);
util.httpEntity = new HttpEntity<Object>(util.params, util.headers);
return util;
}
}
public static RestUtilBuilder restUtil() {
return new RestUtilBuilder();
}
}
package com.debopam.services.policyenquiryservice.rest.util;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.http.ResponseEntity;
import org.springframework.util.concurrent.ListenableFutureCallback;
/**
Response Call back for Async Call
*/
public abstract class ResponseCallBack<T> implements ListenableFutureCallback<ResponseEntity<T>>{
private static final Logger logger = LoggerFactory.getLogger(ResponseCallBack.class.getName());
Map<String,Object> inputs;
public ResponseCallBack(Map<String,Object> inputs){
this.inputs = inputs;
}
@Override
public void onSuccess(ResponseEntity<T> stringResponseEntity) {
onCallSuccess(this.inputs,stringResponseEntity);
}
@Override
public void onFailure(Throwable ex) {
logger.error(ex.getMessage(),ex);
onCallFailure(this.inputs, ex);
}
//Do your stuff
public abstract void onCallSuccess(Map<String,Object> inputs,ResponseEntity<T> stringResponseEntity);
public abstract void onCallFailure(Map<String,Object> inputs,Throwable ex);
}
//Example
private void createRestUtilForAsync()
{
RestUtil restUtil = RestUtil.restUtil().url(url).addHeader("Accept", "application/json").addHeader("Content-Type", "application/json").addparam("xxx", 10).addparam("yyyy", "").addparam("zzz", "dsadsa").httpMethod(HttpMethod.POST).responseType(Policy.class).build();
//create inputs
ResponseCallBack<Policy> responseCallBack = new ResponseContractValuesCallBack(inputs);
//asyncRestTemplate is autowired in the class
restUtil.callServiceAsync(this.asyncRestTemplate, responseCallBack);
}
private void createRestUtilForSync()
{
RestUtil restUtil = RestUtil.restUtil().url(url).addHeader("Accept", "application/json").addHeader("Content-Type", "application/json").addparam("xxx", 10).addparam("yyyy", "").addparam("zzz", "dsadsa").httpMethod(HttpMethod.POST).responseType(Policy.class).build();
//asyncRestTemplate is autowired in the class
Foo foo = restUtil.callServiceAsync(this.restTemplate);
}
您可以使用 Spring Cloud 提供的技術。 例如,對於請求其他 Web 服務,最好的方法是使用 Feign Client。 對於處理 Hystrix 的異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.