溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Jersey客戶端請求Spring Boot(RESTFul)服務的示例

發布時間:2021-02-22 09:46:24 來源:億速云 閱讀:249 作者:小新 欄目:編程語言

這篇文章主要介紹了使用Jersey客戶端請求Spring Boot(RESTFul)服務的示例,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

使用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類型,同時也支持泛型類型的返回值,在上面的示例中,我們使用了大量的泛型,這里就不做過多的解釋了。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“使用Jersey客戶端請求Spring Boot(RESTFul)服務的示例”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女