简体   繁体   English

DropWizard / Jersey API客户端

[英]DropWizard/Jersey API Clients

DropWizard uses Jersey under the hood for REST. DropWizard在引擎盖下使用Jersey进行REST。 I am trying to figure out how to write a client for the RESTful endpoints my DropWizard app will expose. 我试图找出如何为我的DropWizard应用程序将公开的RESTful端点编写客户端。

For the sake of this example, let's say my DropWizard app has a CarResource , which exposes a few simple RESTful endpoints for CRUDding cars: 为了这个例子,让我们说我的DropWizard应用程序有一个CarResource ,它为CRUDding汽车公开了一些简单的RESTful端点:

@Path("/cars")
public class CarResource extends Resource {
    // CRUDs car instances to some database (DAO).
    public CardDao carDao = new CarDao();

    @POST
    public Car createCar(String make, String model, String rgbColor) {
        Car car = new Car(make, model, rgbColor);
        carDao.saveCar(car);

        return car;
    }

    @GET
    @Path("/make/{make}")
    public List<Car> getCarsByMake(String make) {
        List<Car> cars = carDao.getCarsByMake(make);
        return cars;
    }
}

So I would imagine that a structured API client would be something like a CarServiceClient : 所以,我会想象一个结构化的API客户端会像一个CarServiceClient

// Packaged up in a JAR library. Can be used by any Java executable to hit the Car Service
// endpoints.
public class CarServiceClient {
    public HttpClient httpClient;

    public Car createCar(String make, String model, String rgbColor) {
        // Use 'httpClient' to make an HTTP POST to the /cars endpoint.
        // Needs to deserialize JSON returned from server into a `Car` instance.
        // But also needs to handle if the server threw a `WebApplicationException` or
        // returned a NULL.
    }

    public List<Car> getCarsByMake(String make) {
        // Use 'httpClient' to make an HTTP GET to the /cars/make/{make} endpoint.
        // Needs to deserialize JSON returned from server into a list of `Car` instances.
        // But also needs to handle if the server threw a `WebApplicationException` or
        // returned a NULL.
    }
}

But the only two official references to Drop Wizard clients I can find are totally contradictory to one another: 但我能找到的只有两个对Drop Wizard客户的官方引用完全相互矛盾:

  • DropWizard recommended project structure - which claims I should put my client code in a car-client project under car.service.client package; DropWizard建议项目结构 - 声称我应该将我的客户端代码放在car.service.client包下的car-client项目中; but then... 但是之后...
  • DropWizard Client manual - which makes it seem like a "DropWizard Client" is meant for integrating my DropWizard app with other RESTful web services (thus acting as a middleman). DropWizard客户端手册 - 使其看起来像“DropWizard客户端”,用于将我的DropWizard应用程序与其他 RESTful Web服务集成(因此充当中间人)。

So I ask, what is the standard way of writing Java API clients for your DropWizard web services? 所以我想问一下,为DropWizard Web服务编写Java API客户端的标准方法是什么? Does DropWizard have a client-library I can utilize for this type of use case? DropWizard有一个我可以用于此类用例的客户端库吗? Am I supposed to be implementing the client via some Jersey client API? 我应该通过一些Jersey客户端API实现客户端吗? Can someone add pseudo-code to my CarServiceClient so I can understand how this would work? 有人可以将伪代码添加到我的CarServiceClient这样我就可以理解这是如何工作的吗?

Here is a pattern you can use using the JAX-RS client. 这是您可以使用JAX-RS客户端使用的模式。

To get the client: 获得客户:

javax.ws.rs.client.Client init(JerseyClientConfiguration config, Environment environment) {
    return new JerseyClientBuilder(environment).using(config).build("my-client");
}

You can then make calls the following way: 然后,您可以通过以下方式拨打电话:

javax.ws.rs.core.Response post = client
        .target("http://...")
        .request(MediaType.APPLICATION_JSON)
        .header("key", value)
        .accept(MediaType.APPLICATION_JSON)
        .post(Entity.json(myObj));

Yes, what dropwizard-client provides is only to be used by the service itself, most likely to communicate other services. 是的,dropwizard-client提供的只是服务本身使用,最有可能与其他服务进行通信。 It doesn't provide anything for client applications directly. 它不直接为客户端应用程序提供任何内容。

It doesn't do much magic with HttpClients anyway. 无论如何,它对HttpClients没有太多魔力。 It simply configures the client according to the yml file, assigns the existing Jackson object mapper and validator to Jersey client, and I think reuses the thread pool of the application. 它只是根据yml文件配置客户端,将现有的Jackson对象映射器和验证器分配给Jersey客户端,我认为重用应用程序的线程池。 You can check all that on https://github.com/dropwizard/dropwizard/blob/master/dropwizard-client/src/main/java/io/dropwizard/client/JerseyClientBuilder.java 您可以在https://github.com/dropwizard/dropwizard/blob/master/dropwizard-client/src/main/java/io/dropwizard/client/JerseyClientBuilder.java上查看所有内容。

I think I'd go about and structure my classes as you did using Jersey Client. 我想我会像使用Jersey Client那样构建我的类。 Following is an abstract class I've been using for client services: 以下是我一直用于客户端服务的抽象类:

public abstract class HttpRemoteService {

  private static final String AUTHORIZATION_HEADER = "Authorization";
  private static final String TOKEN_PREFIX = "Bearer ";

  private Client client;

  protected HttpRemoteService(Client client) {
    this.client = client;
  }

  protected abstract String getServiceUrl();  

  protected WebResource.Builder getSynchronousResource(String resourceUri) {
    return client.resource(getServiceUrl() + resourceUri).type(MediaType.APPLICATION_JSON_TYPE);
  }

  protected WebResource.Builder getSynchronousResource(String resourceUri, String authToken) {
    return getSynchronousResource(resourceUri).header(AUTHORIZATION_HEADER, TOKEN_PREFIX + authToken);
  }

  protected AsyncWebResource.Builder getAsynchronousResource(String resourceUri) {
    return client.asyncResource(getServiceUrl() + resourceUri).type(MediaType.APPLICATION_JSON_TYPE);
  }

  protected AsyncWebResource.Builder getAsynchronousResource(String resourceUri, String authToken) {
    return getAsynchronousResource(resourceUri).header(AUTHORIZATION_HEADER, TOKEN_PREFIX + authToken);
  }

  protected void isAlive() {
    client.resource(getServiceUrl()).get(ClientResponse.class);
  }  

}

and here is how I make it concrete: 这就是我如何使它具体化:

private class TestRemoteService extends HttpRemoteService {

    protected TestRemoteService(Client client) {
      super(client);
    }

    @Override
    protected String getServiceUrl() {
      return "http://localhost:8080";
    }

    public Future<TestDTO> get() {
      return getAsynchronousResource("/get").get(TestDTO.class);
    }

    public void post(Object object) {
      getSynchronousResource("/post").post(object);
    }

    public void unavailable() {
      getSynchronousResource("/unavailable").get(Object.class);
    }

    public void authorize() {
      getSynchronousResource("/authorize", "ma token").put();
    }
  }

if anyone is trying to use DW 0.8.2 when building a client, and you're getting the following error: 如果有人在构建客户端时尝试使用DW 0.8.2,并且您收到以下错误:

cannot access org.apache.http.config.Registry
class file for org.apache.http.config.Registry not found

at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:858)
at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:129)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
... 19 more

update your dropwizard-client in your pom.xml from 0.8.2 to 0.8. 将pom.xml中的dropwizard-client从0.8.2更新为0.8。 4 and you should be good. 4 ,你应该好。 I believe a jetty sub-dependency was updated which fixed it. 我相信一个码头子依赖项已更新,修复了它。

    <dependency>
        <groupId>io.dropwizard</groupId>
        <artifactId>dropwizard-client</artifactId>
        <version>0.8.4</version>
        <scope>compile</scope>
    </dependency>

您可以与Spring Framework集成来实现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM