新聞中心
這篇文章主要介紹了使用Jersey客戶端請求Spring Boot(RESTFul)服務(wù)的示例,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
專注于為中小企業(yè)提供網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)臨夏州免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了近千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
使用Jersey客戶端請求Spring Boot(RESTFul)服務(wù),具體如下:
Jersey客戶端獲取Client對象實(shí)例封裝:
@Service("jerseyPoolingClient") public class JerseyPoolingClientFactoryBean implements FactoryBean, InitializingBean, DisposableBean{ /** * Client接口是REST客戶端的基本接口,用于和REST服務(wù)器通信。Client被定義為一個重量級的對象,其內(nèi)部管理著 * 客戶端通信底層的各種對象,比如連接器,解析器等。因此,不推薦在應(yīng)用中產(chǎn)生大量的的Client實(shí)例,這一點(diǎn)在開發(fā)中 * 需要特別小心,另外該接口要求其實(shí)例要有關(guān)閉連接的保障,否則會造成內(nèi)存泄露 */ private Client client; /** * 一個Client最大的連接數(shù),默認(rèn)為2000 */ private int maxTotal = 2000; /** * 每路由的默認(rèn)最大連接數(shù) */ private int defaultMaxPerRoute = 1000; private ClientConfig clientConfig; public JerseyPoolingClientFactoryBean() { } /** * 帶配置的構(gòu)造函數(shù) * @param clientConfig */ public JerseyPoolingClientFactoryBean(ClientConfig clientConfig) { this.clientConfig = clientConfig; } public JerseyPoolingClientFactoryBean(int maxTotal, int defaultMaxPerRoute) { this.maxTotal = maxTotal; this.defaultMaxPerRoute = defaultMaxPerRoute; } /** * attention: * Details:容器銷毀時,釋放Client資源 * @author chhliu */ @Override public void destroy() throws Exception { this.client.close(); } /** * * attention: * Details:以連接池的形式,來初始化Client對象 * @author chhliu */ @Override public void afterPropertiesSet() throws Exception { // 如果沒有使用帶ClientConfig的構(gòu)造函數(shù),則該類的實(shí)例為null,則使用默認(rèn)的配置初始化 if(this.clientConfig == null){ final ClientConfig clientConfig = new ClientConfig(); // 連接池管理實(shí)例,該類是線程安全的,支持多并發(fā)操作 PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(); pcm.setMaxTotal(this.maxTotal); pcm.setDefaultMaxPerRoute(this.defaultMaxPerRoute); clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, pcm); /* * 在使用Jersey來請求Spring Boot服務(wù)時,Spring Boot默認(rèn)使用Jackson來解析JSON * 而Jersey默認(rèn)使用MOXy解析JSON,當(dāng)Jersey Client想Spring Boot服務(wù)請求資源時, * 這個差異會導(dǎo)致服務(wù)端和客戶端對POJO的轉(zhuǎn)換不同,造成反序列化的錯誤 * 因此,此處需要在Client的Config實(shí)例中注冊Jackson特性 */ clientConfig.register(JacksonFeature.class); // 使用配置Apache連接器,默認(rèn)連接器為HttpUrlConnector clientConfig.connectorProvider(new ApacheConnectorProvider()); client = ClientBuilder.newClient(clientConfig); }else{ // 使用構(gòu)造函數(shù)中的ClientConfig來初始化Client對象 client = ClientBuilder.newClient(this.clientConfig); } } /** * attention: * Details:返回Client對象,如果該對象為null,則創(chuàng)建一個默認(rèn)的Client * @author chhliu */ @Override public Client getObject() throws Exception { if(null == this.client){ return ClientBuilder.newClient(); } return this.client; } /** * attention: * Details:獲取Client對象的類型 * @author chhliu */ @Override public Class> getObjectType() { return (this.client == null ? Client.class : this.client.getClass()); } /** * attention: * Details:Client對象是否為單例,默認(rèn)為單例 * @author chhliu */ @Override public boolean isSingleton() { return true; } }
請求Spring Boot服務(wù)的封裝:
@Component("jerseyClient") public class JerseyClient { @Resource(name="jerseyPoolingClient") private Client client; /** * attention: * Details:通過id來查詢對象 * @author chhliu */ public ResultMsggetResponseById(final String id) throws JsonProcessingException, IOException{ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/user/"+id); Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType > genericType = new GenericType >(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ /* * 當(dāng)調(diào)用readEntity方法時,程序會自動的釋放連接 * 即使沒有調(diào)用readEntity方法,直接返回泛型類型的對象,底層仍然會釋放連接 */ return response.readEntity(genericType); }else{ ResultMsg res = new ResultMsg (); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details:分頁查詢 * @author chhliu */ public ResultMsg > getGithubWithPager(final Integer pageOffset, final Integer pageSize, final String orderColumn){ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/users/page") .queryParam("pageOffset", pageOffset) .queryParam("pageSize", pageSize) .queryParam("orderColumn", orderColumn); // 注意,如果此處的媒體類型為MediaType.APPLICATION_JSON,那么對應(yīng)的服務(wù)中的參數(shù)前需加上@RequestBody Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType >> genericType = new GenericType >>(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg > res = new ResultMsg >(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details:根據(jù)用戶名來查詢 * @author chhliu */ public ResultMsg > getResponseByUsername(final String username) throws JsonProcessingException, IOException{ WebTarget webTarget = client.target("http://localhost:8080").path("/github/get/users/"+username); Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); GenericType
>> genericType = new GenericType >>(){}; Response response = invocationBuilder.get(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg > res = new ResultMsg
>(); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details:根據(jù)id來刪除一個記錄 * @author chhliu */ public ResultMsg
deleteById(final String id) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/delete/"+id); GenericType > genericType = new GenericType >(){}; Response response = target.request().delete(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg res = new ResultMsg (); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details:更新一條記錄 * @author chhliu */ public ResultMsg update(final GitHubEntity entity) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/put"); GenericType > genericType = new GenericType >(){}; Response response = target.request().buildPut(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg res = new ResultMsg (); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } /** * attention: * Details:插入一條記錄 * @author chhliu */ public ResultMsg save(final GitHubEntity entity) throws JsonProcessingException, IOException{ WebTarget target = client.target("http://localhost:8080").path("/github/post"); GenericType > genericType = new GenericType >(){}; Response response = target.request().buildPost(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke(); if(response.getStatus() == 200){ return response.readEntity(genericType); }else{ ResultMsg res = new ResultMsg (); res.setErrorCode(String.valueOf(response.getStatus())); res.setErrorMsg(response.getStatusInfo().toString()); res.setOK(false); return res; } } }
Jersey客戶端接口詳解
1 Client接口
創(chuàng)建一個Client實(shí)例是通過ClientBuilder構(gòu)造的,通常使用一個ClientConfig實(shí)例作為參數(shù),如果我們使用Client client = ClientBuilder.newClient()的方式來創(chuàng)建Client實(shí)例的時候,每次都會創(chuàng)建一個Client實(shí)例,但該實(shí)例是一個重量級的對象,所以,建議使用HTTP連接池的方式來管理連接,而不是每次請求都去創(chuàng)建一個Client對象,具體的連接池管理方式見上面的代碼示例。
2 WebTarget接口
WebTarget接口是為REST客戶端實(shí)現(xiàn)資源定位的接口,通過WebTarget接口,我們可以定義請求資源的具體地址,查詢參數(shù)和媒體類型信息等。我們可以通過方法鏈的方式完成對一個WebTarget實(shí)例的配置,但是需要注意的是,雖然WebTarget的使用方式和StringBuffer的方法鏈方式非常類似,但實(shí)質(zhì)是不一樣的,WebTarget的方法鏈必須設(shè)置方法的返回值,作為后續(xù)流程的句柄,這個是什么意思了,看下面的幾個示例:
示例1:StringBuffer的方法鏈?zhǔn)纠?/p>
StringBuffer sb = new StringBuffer("lch"); sb.append("hello"); sb.append("world"); sb.append("hello").append("world"); // 這種方式和上面的兩行代碼實(shí)現(xiàn)的效果是一樣的。
示例2:WebTarget的方法鏈?zhǔn)纠?/p>
// 使用一行代碼的方法鏈來實(shí)例化WebTarget WebTarget webTarget = client.target("http://localhost:8080"); webTarget.path("/github/get/users/page") .queryParam("pageOffset", pageOffset) .queryParam("pageSize", pageSize) .queryParam("orderColumn", orderColumn); // 下面是分開使用方法鏈來實(shí)例化WebTarget webTarget.path("/github/get/users/page"); webTarget.queryParam("pageOffset", pageOffset); webTarget.queryParam("pageSize", pageSize); // 上面兩種實(shí)例化的方式最后產(chǎn)生的結(jié)果大相徑庭,上面的實(shí)例化方式是OK的,沒有問題,下面的實(shí)例化方式卻有問題,下面的實(shí)例化方式中,每一行都會生成一個 // 新的WebTarget對象,原來的WebTarget并沒有起任何作用,畢竟每一行的實(shí)例都不一樣,如果我們想要分多行實(shí)例化了,就必須為每個方法的返回提供一個句柄,方式如下: WebTarget target = client.target("http://localhost:8080"); WebTarget pathTarget = target.path("/github/get/users/page"); WebTarget paramTarget = pathTarget.queryParam("pageOffset", pageOffset); // 最后使用的時候,用最后一個WebTarget實(shí)例對象即可
3 Invocation接口
Invocation接口是在完成資源定位配置后,向REST服務(wù)端發(fā)起請求的接口,請求包括同步和異步兩種方式,由Invocation接口內(nèi)部的Builder接口定義,Builder接口繼承了同步接口SyncInvoker,異步調(diào)用的使用示例如下:
Future>> response = invocationBuilder.async().get(genericType); if(response.isDone()){ return response.get(); }
Invocation.Builder接口實(shí)例分別執(zhí)行了GET和POST請求來提交查詢和創(chuàng)建,默認(rèn)情況下,HTTP方法調(diào)用的返回類型是Response類型,同時也支持泛型類型的返回值,在上面的示例中,我們使用了大量的泛型,這里就不做過多的解釋了。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“使用Jersey客戶端請求Spring Boot(RESTFul)服務(wù)的示例”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
新聞名稱:使用Jersey客戶端請求SpringBoot(RESTFul)服務(wù)的示例
網(wǎng)站URL:http://fisionsoft.com.cn/article/pghcig.html