帶提供程式的基本 Webclient
要開始,我們需要一個生產 WebClient 的工廠。
public class ClientFactory {
private Map<String, WebClient> cache = new HashMap<>();
public enum RESTClient {
PORTAL;
}
public WebClient fetchRestClient(RESTClient restClient) {
if (this.cache.containsKey(restClient)) {
return WebClient.fromClient(this.cache.get(rc));
}
if (RESTClient.enum.equals(rc)) {
List<Object> providers = new ArrayList<Object>();
providers.add(new GsonMessageBodyProvider());
WebClient webClient = WebClient.create("https://blah.com", providers);
HTTPConduit conduit = WebClient.getConfig(webClient).getHttpConduit();
conduit.getClient().setReceiveTimeout(recieveTimeout);
conduit.getClient().setConnectionTimeout(connectionTimout);
this.cache.put(RESTClient.CAT_DEVELOPER_PORTAL.name(), webClient);
return WebClient.fromClient(webClient);// thread safe
}
}
}
- 首先,我們建立一個提供者列表(稍後會介紹)
- 接下來,我們使用靜態工廠“
create()
”建立一個新的 webclient。在這裡,我們可以新增一些其他的東西,如 Basic Auth creds 和執行緒安全。現在只需使用這個。 - 接下來,我們拉出 HTTPConduit 並設定超時。CXF 附帶 Java 基類客戶端,但你可以使用 Glassfish 或其他客戶端。
- 最後我們快取 WebClient。這很重要,因為到目前為止,程式碼的建立成本很高。下一行顯示瞭如何使其執行緒安全。請注意,這也是我們從快取中提取程式碼的方式。基本上我們正在製作 REST 呼叫的模型,然後在每次需要時克隆它。
- 請注意這裡沒有的內容:我們沒有新增任何引數或 URL。這些可以在這裡新增,但這將產生一個特定的端點,我們想要一個通用的端點。此外,請求中沒有新增標頭。這些不會超過克隆,因此必須在以後新增。
現在我們有了一個準備好的 WebClient。讓我們設定其餘的通話。
public Person fetchPerson(Long id) {
long timer t = System.currentTimeMillis();
Person person = null;
try {
wc = this.factory.findWebClient(RESTClient.PORTAL);
wc.header(AUTH_HEADER, SUBSCRIPTION_KEY);
wc.header(HttpHeaders.ACCEPT, "application/person-v1+json");
wc.path("person").path("base");
wc.query("id", String.valueOf(id));
person = wc.get(Person.class);
}
catch (WebApplicationException wae) {
// we wanna skip these. They will show up in the "finally" logs.
}
catch (Exception e) {
log.error(MessageFormat.format("Error fetching Person: id:{0} ", id), e);
}
finally {
log.info("GET HTTP:{} - Time:[{}ms] - URL:{} - Content-Type:{}", wc.getResponse().getStatus(), (System.currentTimeMillis() - timer), wc.getCurrentURI(), wc.getResponse().getMetadata().get("content-type"));
wc.close();
}
return p;
}
- 在嘗試中,我們從工廠中獲取 WebClient。這是一個新的冷淡的。
- 接下來我們設定一些標題。在這裡,我們新增一些 Auth 標頭,然後新增一個接受標頭。請注意我們有一個自定義接受標頭。
- 接下來是新增路徑和查詢字串。請記住,這些步驟沒有順序。
- 最後我們做得到。當然,有幾種方法可以做到這一點。在這裡,我們讓 CXF 為我們做 JSON 對映。完成這種方式後,我們必須處理 WebApplicationExceptions。因此,如果我們得到 404,CXF 將丟擲異常。請注意,我在那裡吃了那些例外,因為我只是在最後記錄響應。但是,我確實希望得到任何其他例外,因為它們可能很重要。
- 如果你不喜歡此異常處理切換,則可以從
get
返回 Response 物件。該物件包含實體和 HTTP 狀態程式碼。它永遠不會丟擲 WebApplicationException。唯一的缺點是它沒有為你執行 JSON 對映。 - 最後,在
finally
子句中,我們有一個“wc.close()
”。如果從 get 子句中獲取物件,則不必執行此操作。雖然有些東西可能會出錯,但這是一個很好的故障保險。
那麼,那個接受標題呢:application / person-v1 + json CXF 如何知道如何解析它?CXF 附帶了一些內建的 JSON 解析器,但我想使用 Gson。Json 解析器的許多其他實現需要某種註釋但不需要 Gson。它很容易使用。
public class GsonMessageBodyProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {
private Gson gson = new GsonBuilder().create();
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return StringUtils.endsWithIgnoreCase(mediaType.getSubtype(), "json");
}
@Override
public T readFrom(Class<T> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
try {
return gson.fromJson(new BufferedReader(new InputStreamReader(entityStream, "UTF-8")), type);
}
catch (Exception e) {
throw new IOException("Trouble reading into:" + type.getName(), e);
}
}
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return StringUtils.containsIgnoreCase(mediaType.getSubtype(), "json");
}
@Override
public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return 0;
}
@Override
public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
try {
JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
writer.setIndent(" ");
gson.toJson(t, type, writer);
writer.close();
}
catch (Exception e) {
throw new IOException("Trouble marshalling:" + type.getName(), e);
}
}
}
程式碼很簡單。你實現了兩個介面:MessageBodyReader 和 MessageBodyWriter(或只是一個),然後在建立 WebClient 時將其新增到提供者。CXF 從中得出結論。一種選擇是在“isReadable()
”“isWriteable()
”方法中返回 true
。這將確保 CXF 使用此類而不是所有內建類。將首先檢查新增的提供程式。