詳解如何使用Jersey用戶端請求Spring Boot(RESTFul)服務,jerseyrestful

來源:互聯網
上載者:User

詳解如何使用Jersey用戶端請求Spring Boot(RESTFul)服務,jerseyrestful

本文介紹了使用Jersey用戶端請求Spring Boot(RESTFul)服務,分享給大家,具體如下:

Jersey用戶端擷取Client對象執行個體封裝:

@Service("jerseyPoolingClient") public class JerseyPoolingClientFactoryBean implements FactoryBean<Client>, InitializingBean, DisposableBean{      /**    * Client介面是REST用戶端的基本介面,用於和REST伺服器通訊。Client被定義為一個重量級的對象,其內部管理著    * 用戶端通訊底層的各種對象,比如連接器,解析器等。因此,不推薦在應用中產生大量的的Client執行個體,這一點在開發中    * 需要特別小心,另外該介面要求其執行個體要有關閉串連的保障,否則會造成記憶體泄露    */   private Client client;      /**    * 一個Client最大的串連數,預設為2000    */   private int maxTotal = 2000;      /**    * 每路由的預設最大串連數    */   private int defaultMaxPerRoute = 1000;      private ClientConfig clientConfig;      public JerseyPoolingClientFactoryBean() {   }      /**    * 帶配置的建構函式    * @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的建構函式,則該類的執行個體為null,則使用預設的配置初始化     if(this.clientConfig == null){       final ClientConfig clientConfig = new ClientConfig();       // 串連池管理執行個體,該類是安全執行緒的,支援多並行作業       PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager();       pcm.setMaxTotal(this.maxTotal);       pcm.setDefaultMaxPerRoute(this.defaultMaxPerRoute);              clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, pcm);       /*        * 在使用Jersey來請求Spring Boot服務時,Spring Boot預設使用Jackson來解析JSON        * 而Jersey預設使用MOXy解析JSON,當Jersey Client想Spring Boot服務要求資源時,        * 這個差異會導致服務端和用戶端對POJO的轉換不同,造成還原序列化的錯誤        * 因此,此處需要在Client的Config執行個體中註冊Jackson特性        */       clientConfig.register(JacksonFeature.class);       // 使用配置Apache連接器,預設連接器為HttpUrlConnector       clientConfig.connectorProvider(new ApacheConnectorProvider());       client = ClientBuilder.newClient(clientConfig);     }else{       // 使用建構函式中的ClientConfig來初始化Client對象       client = ClientBuilder.newClient(this.clientConfig);     }   }    /**    * attention:    * Details:返回Client對象,如果該對象為null,則建立一個預設的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對象是否為單例,預設為單例    * @author chhliu    */   @Override   public boolean isSingleton() {     return true;   } } 

請求Spring Boot服務的封裝:

@Component("jerseyClient") public class JerseyClient {      @Resource(name="jerseyPoolingClient")   private Client client;      /**    * attention:    * Details:通過id來查詢對象    * @author chhliu    */   public ResultMsg<GitHubEntity> getResponseById(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<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){};     Response response = invocationBuilder.get();     if(response.getStatus() == 200){       /*        * 當調用readEntity方法時,程式會自動的釋放串連        * 即使沒有調用readEntity方法,直接返回泛型型別的對象,底層仍然會釋放串連        */       return response.readEntity(genericType);     }else{       ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;     }   }      /**    * attention:    * Details:分頁查詢    * @author chhliu    */   public ResultMsg<Pager<GitHubEntity>> 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,那麼對應的服務中的參數前需加上@RequestBody         Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);     GenericType<ResultMsg<Pager<GitHubEntity>>> genericType = new GenericType<ResultMsg<Pager<GitHubEntity>>>(){};     Response response = invocationBuilder.get();     if(response.getStatus() == 200){       return response.readEntity(genericType);     }else{       ResultMsg<Pager<GitHubEntity>> res = new ResultMsg<Pager<GitHubEntity>>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;     }        }      /**    * attention:    * Details:根據使用者名稱來查詢    * @author chhliu    */   public ResultMsg<List<GitHubEntity>> 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<ResultMsg<List<GitHubEntity>>> genericType = new GenericType<ResultMsg<List<GitHubEntity>>>(){};     Response response = invocationBuilder.get();     if(response.getStatus() == 200){       return response.readEntity(genericType);     }else{       ResultMsg<List<GitHubEntity>> res = new ResultMsg<List<GitHubEntity>>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;     }   }      /**    * attention:    * Details:根據id來刪除一個記錄    * @author chhliu    */   public ResultMsg<GitHubEntity> deleteById(final String id) throws JsonProcessingException, IOException{     WebTarget target = client.target("http://localhost:8080").path("/github/delete/"+id);     GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){};     Response response = target.request().delete();     if(response.getStatus() == 200){       return response.readEntity(genericType);     }else{       ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;     }   }      /**    * attention:    * Details:更新一條記錄    * @author chhliu    */   public ResultMsg<GitHubEntity> update(final GitHubEntity entity) throws JsonProcessingException, IOException{     WebTarget target = client.target("http://localhost:8080").path("/github/put");     GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){};     Response response = target.request().buildPut(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke();     if(response.getStatus() == 200){       return response.readEntity(genericType);     }else{       ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;     }   }      /**    * attention:    * Details:插入一條記錄    * @author chhliu    */   public ResultMsg<GitHubEntity> save(final GitHubEntity entity) throws JsonProcessingException, IOException{       WebTarget target = client.target("http://localhost:8080").path("/github/post");      GenericType<ResultMsg<GitHubEntity>> genericType = new GenericType<ResultMsg<GitHubEntity>>(){};      Response response = target.request().buildPost(Entity.entity(entity, MediaType.APPLICATION_JSON)).invoke();      if(response.getStatus() == 200){        return response.readEntity(genericType);      }else{       ResultMsg<GitHubEntity> res = new ResultMsg<GitHubEntity>();       res.setErrorCode(String.valueOf(response.getStatus()));       res.setErrorMsg(response.getStatusInfo().toString());       res.setOK(false);       return res;      }   } } 

Jersey用戶端介面詳解

1 Client介面

建立一個Client執行個體是通過ClientBuilder構造的,通常使用一個ClientConfig執行個體作為參數,如果我們使用Client client = ClientBuilder.newClient()的方式來建立Client執行個體的時候,每次都會建立一個Client執行個體,但該執行個體是一個重量級的對象,所以,建議使用HTTP串連池的方式來管理串連,而不是每次請求都去建立一個Client對象,具體的串連池管理方式見上面的程式碼範例。

2 WebTarget介面

WebTarget介面是為REST用戶端實現資源定位的介面,通過WebTarget介面,我們可以定義請求資源的具體地址,查詢參數和媒體類型資訊等。我們可以通過方法鏈的方式完成對一個WebTarget執行個體的配置,但是需要注意的是,雖然WebTarget的使用方式和StringBuffer的方法鏈方式非常類似,但實質是不一樣的,WebTarget的方法鏈必須設定方法的傳回值,作為後續流程的控制代碼,這個是什麼意思了,看下面的幾個樣本:

樣本1:StringBuffer的方法鏈樣本

StringBuffer sb = new StringBuffer("lch");      sb.append("hello");      sb.append("world");      sb.append("hello").append("world"); // 這種方式和上面的兩行代碼實現的效果是一樣的。 

樣本2:WebTarget的方法鏈樣本

// 使用一行代碼的方法鏈來執行個體化WebTarget WebTarget webTarget = client.target("http://localhost:8080"); webTarget.path("/github/get/users/page")   .queryParam("pageOffset", pageOffset)   .queryParam("pageSize", pageSize)   .queryParam("orderColumn", orderColumn); // 下面是分開使用方法鏈來執行個體化WebTarget webTarget.path("/github/get/users/page"); webTarget.queryParam("pageOffset", pageOffset); webTarget.queryParam("pageSize", pageSize); // 上面兩種執行個體化的方式最後產生的結果大相徑庭,上面的執行個體化方式是OK的,沒有問題,下面的執行個體化方式卻有問題,下面的執行個體化方式中,每一行都會產生一個 // 新的WebTarget對象,原來的WebTarget並沒有起任何作用,畢竟每一行的執行個體都不一樣,如果我們想要分多行執行個體化了,就必須為每個方法的返回提供一個控制代碼,方式如下:  WebTarget target = client.target("http://localhost:8080"); WebTarget pathTarget = target.path("/github/get/users/page"); WebTarget paramTarget = pathTarget.queryParam("pageOffset", pageOffset);  // 最後使用的時候,用最後一個WebTarget執行個體對象即可 

3 Invocation介面

Invocation介面是在完成資源定位配置後,向REST服務端發起請求的介面,請求包括同步和非同步兩種方式,由Invocation介面內部的Builder介面定義,Builder介面繼承了同步介面SyncInvoker,非同步呼叫的使用樣本如下:

Future<ResultMsg<List<GitHubEntity>>> response = invocationBuilder.async().get(genericType);      if(response.isDone()){       return response.get();     } 

Invocation.Builder介面執行個體分別執行了GET和POST請求來提交查詢和建立,預設情況下,HTTP方法調用的傳回型別是Response類型,同時也支援泛型型別的傳回值,在上面的樣本中,我們使用了大量的泛型,這裡就不做過多的解釋了。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.