详解如何使用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类型,同时也支持泛型类型的返回值,在上面的示例中,我们使用了大量的泛型,这里就不做过多的解释了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • SpringBoot整合jersey的示例代码
(0)

相关推荐

  • SpringBoot整合jersey的示例代码

    这篇文章主要从以下几个方面来介绍.简单介绍下jersey,springboot,重点介绍如何整合springboot与jersey. 什么是jersey 什么是springboot 为什么要使用springboot+jersey 如何整合springboot与jersey 什么是jersey 阅读官方文档请点击:jsersey.RESTful Web Services in Java即java中的一种restful框架.jersey使用了JAX-RS规范来约束API的开发.既然jersey是基于

  • 详解如何使用Jersey客户端请求Spring Boot(RESTFul)服务

    本文介绍了使用Jersey客户端请求Spring Boot(RESTFul)服务,分享给大家,具体如下: Jersey客户端获取Client对象实例封装: @Service("jerseyPoolingClient") public class JerseyPoolingClientFactoryBean implements FactoryBean<Client>, InitializingBean, DisposableBean{ /** * Client接口是REST

  • 详解在Docker容器中运行Spring Boot应用

    spring Boot简化了Spring应用的开发过程,遵循约定优先配置的原则提供了各类开箱即用(out-of-the-box)的框架配置.另一方面,Spring Boot还具备将代码直接构建为可执行jar包的能力,这个jar包是一个可以独立运行的部署单元.基于以上特性,现在普遍认为Spring Boot提供了一种快速构造微服务(Micro-Service)的能力. Docker与Spring Boot Docker是一种Linux容器的实现,Linux容器是基于进程的轻量级资源隔离技术,每一个

  • 详解eclipse下创建第一个spring boot项目

    spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者.也就是说,Spring Boot是为了简化Spring开发而生,主要思想是降低spring的入门,使得新手可以以最快的速度让程序在spring框架下跑起来. 今天我们就来创建

  • 详解用Kotlin写一个基于Spring Boot的RESTful服务

    Spring太复杂了,配置这个东西简直就是浪费生命.尤其在没有什么并发压力,随便搞一个RESTful服务,让整个业务跑起来先的情况下,更是么有必要纠结在一堆的XML配置上.显然这么想的人是很多的,于是就有了Spring Boot.又由于Java 8太墨迹于是有了Kotlin. 数据源使用MySql.通过Spring Boot这个基本不怎么配置的,不怎么微的微框架的Spring Data JPA和Hibernate来访问数据. 处理依赖 这里使用Gradle来处理依赖. 首先下载官网给的初始项目:

  • 详解Guava Cache本地缓存在Spring Boot应用中的实践

    概述 在如今高并发的互联网应用中,缓存的地位举足轻重,对提升程序性能帮助不小.而 3.x开始的 Spring也引入了对 Cache的支持,那对于如今发展得如火如荼的 Spring Boot来说自然也是支持缓存特性的.当然 Spring Boot默认使用的是 SimpleCacheConfiguration,即使用 ConcurrentMapCacheManager 来实现的缓存.但本文将讲述如何将 Guava Cache缓存应用到 Spring Boot应用中. Guava Cache是一个全内

  • Java Spring Boot消息服务万字详解分析

    目录 消息服务概述 为什么要使用消息服务 异步处理 应用解耦 流量削峰 分布式事务管理 常用消息中间件介绍 ActiveMQ RabbitMQ RocketMQ RabbitMQ消息中间件 RabbitMQ简介 RabbitMQ工作模式介绍 Work queues(工作队列模式) Public/Subscribe(发布订阅模式) Routing(路由模式) Topics(通配符模式) RPC Headers RabbitMQ安装以及整合环境搭建 安装RabbitMQ 下载RabbitMQ 安装R

  • Spring boot admin 服务监控利器详解

    目录 一.简介 二.搭建 1.服务端 2.客户端 3.启动项目 4.客户端配置 3.微服务 3.1.服务端 3.2.客户端 4.我的微服务预警发送其他服务状态信息思路 一.简介 用于对 Spring Boot 应用的管理和监控.可以用来监控服务是否健康.是否在线.以及一些jvm数据等等.Spring Boot Admin 分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client),服务端和客户端之间采用 http 通讯方式实现数据交

  • spring boot微服务自定义starter原理详解

    这篇文章主要介绍了spring boot微服务自定义starter原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 使用spring boot开发微服务后,工程的数量大大增加(一定要按照领域来切,不要一个中间件客户端包一个),让各个jar从开发和运行时自包含成了一个重要的内容之一.spring boot starter就可以用来解决该问题(没事启动时别依赖于applicationContext.getBean获取bean进行处理,依赖关系

  • 详解Golang语言HTTP客户端实践

    目录 HTTP客户端封装 测试脚本 测试服务 最近在学习Golang语言,中间遇到一个前辈指点,有一个学习原则:Learning By Doing.跟我之前学习Java的经验高度契合.在前一段时间学习洼坑中挣扎了好几天,差点就忘记这个重要的成功经验. 那么那什么来做练习呢?当然结合当下的工作啦,所以我列了一个路线给自己,那就是从接口测试开始学起来,从功能测试到性能测试,然后掌握基本Server开发技能. 首先,得先把HTTP接口测试常用的几个功能实现了,主要是获取HTTPrequest对象,发送

  • 详解使用fetch发送post请求时的参数处理

    详解使用fetch发送post请求时的参数处理 不考虑古董浏览器之后,使用fetch来发送ajax请求,变得非常爽快和时尚. 但是,发送post请求的时候,把笔者卡了一下.后台如下获取参数时,总是为null String q = req.getParameter("q"); 研究了好久,总算写出正确的使用方式了.直接上代码. fetch("/search/project/", { method: "POST", headers: { 'Conte

随机推荐