接受并返回对象的REST服务。怎么写客户端? [英] REST service that accepts and returns object. How to write client?

查看:139
本文介绍了接受并返回对象的REST服务。怎么写客户端?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经宣布了两个REST Web服务。一个只返回一个对象的人。和其他接受对象并返回另一个对象。
使用POJO Order.java。

I have declared two REST web services. One which simply returns a object. And other which accepts an object and returns another object. POJO Order.java is used.

@XmlRootElement
public class Order {

   private String id;

   private String description;

   public Order() {
   }

   @XmlElement
   public String getId() {
          return id;
   }
   @XmlElement
   public String getDescription() {
          return description;
   }

    // Other setters and methods
}

Webservice定义为

Webservice is defined as

@Path("/orders")
public class OrdersService {
// Return the list of orders for applications with json or xml formats
@Path("/oneOrder")
@GET
@Produces({MediaType.APPLICATION_JSON})
public  Order getOrder_json() {
  System.out.println("inside getOrder_json");
  Order o1 = OrderDao.instance.getOrderFromId("1");
  System.out.println("about to return one order");
  return o1;
}

@Path("/writeAndIncrementOrder")
@GET
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
public  Order writeAndIncrementOrder(Order input) {
  System.out.println("inside writeAndIncrementOrder");
  Order o1 = new Order();
  o1.setId(input.getId()+1000);
  o1.setDescription(input.getDescription()+"10000");
  System.out.println("about to return one order");
  return o1;
 }

我可以编写客户端代码来调用不接受任何内容的Web服务返回对象。客户端代码如下

I could write client code to call the web service that does not accept anything but returns object. Client code is as follows

import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.client.ClientConfig;

public class Test {

public static void main(String[] args) {

WebTarget target2 = client.target(getBaseURI()).path("rest").path("orders");
String o2 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class);
        System.out.println(o2);
}

private static URI getBaseURI() {
    return UriBuilder.fromUri("http://localhost:8090/FirstRESTProject").build();
  }

但我不明白如何调用接受以及退货的其他服务宾语。
我在互联网上尝试了不同的解决方案。但没有什么对我有用。某些解决方案仅适用于发送对象,而某些解决方案仅适用于接受。但是没有人能够在一次通话中同时完成这两项工作。

But I do not understand how to call other service which accepts as well as returns object. I tried different solutions given on internet. But nothing worked for me. Some solution works only for sending object and some works only for accepting. But none worked for doing both in one call.

编辑
如下面的建议,我注册了JacksonJaxbJsonProvider.class但是转换为订单对象没有发生。

EDIT As suggested in below answer I registered JacksonJaxbJsonProvider.class But auto-conversion into Order object is not happening.

        String o2 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class);

        client.register(JacksonJaxbJsonProvider.class);
        Order o4 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(Order.class);

在上面的程序中,我成功地将字符串作为{id:1,description: 这是第一个订单}但是获取直接对象会抛出错误
找不到媒体类型= application / json的MessageBodyReader,类型= class shopping.cart.om.Order,genericType = class shopping.cart.om.Order 。

In above program I successfully get string as {"id":"1","description":"This is the 1st order"} But getting direct object throws error MessageBodyReader not found for media type=application/json, type=class shopping.cart.om.Order, genericType=class shopping.cart.om.Order.

推荐答案

如果你花一点时间来理解 WebTarget API,以及通过调用 WebTarget 的方法返回的不同类型,你应该更好地理解如何进行调用。这可能有点令人困惑,因为几乎所有示例都使用方法链接,因为这是一种非常方便的方式,但是这样做,您会错过创建和发送请求所涉及的所有实际类。让我们分解一下

If you take a little bit of time to understand the WebTarget API, as well as the different types returned from calls to WebTarget's method, you should get a better understanding of how to make calls. It may be a little confusing, as almost all the example use method chaining, as it's a very convenient way, but doing this, you miss all the actual classes involved in create and sending the request. Let break it down a bit


WebTarget target = client.target(getBaseURI())。path(rest )。path(orders);

WebTarget.path( )只返回 WebTarget 。没有什么有趣的。

WebTarget.path() simply returns the WebTarget. Nothing interesting there.


target.path(oneOrder)。request()。accept(MediaType.APPLICATION_JSON) ).get(String.class)




  • WebTarget.request()返回 Invocation.Builder

  • Invocation.Builder.accept(。 。)返回 Invocation.Builder

  • Invocation.Builder.get() 调用其超类的 SyncInvoker.get() ,它发出实际请求,并根据我们的参数返回一个类型提供给 get(Class returnType)

    • WebTarget.request() returns Invocation.Builder
    • Invocation.Builder.accept(..) returns Invocation.Builder
    • Invocation.Builder.get() calls its super class's SyncInvoker.get(), which makes the actual request, and returns a type, based on the argument we provide to get(Class returnType)
    • 你正在做什么 get(String.class)表示响应流应该被反序列化为Sting类型的响应。这不是问题,因为JSON本质上只是一个String。但是如果你想将它解组为POJO,那么你需要知道如何将JSON解组为POJO类型的 MessageBodyReader 。杰克逊在 <$ c}中提供 MessageBodyReader $ c> jackson-jaxrs-json-provider 依赖

      What you're doing with get(String.class) is saying that the response stream should be deserialized into a Sting type response. This is not a problem, as JSON is inherently just a String. But if you want to unmarshal it to a POJO, then you need to have a MessageBodyReader that knows how to unmarshal JSON to your POJO type. Jackson provides a MessageBodyReader in it's jackson-jaxrs-json-provider dependency

      <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.4.0</version>
      </dependency>
      

      大多数实现都会为这个模块提供一个包装器,比如 jersey-media-泽西的json-jackson 或Resteasy的 resteasy-jackson-provider 。但他们仍在使用基础 jackson-jaxrs-json-provider

      Most implementations will provider a wrapper for this module, like jersey-media-json-jackson for Jersey or resteasy-jackson-provider for Resteasy. But they are still using the underlying jackson-jaxrs-json-provider.

      这就是说,一旦你有了类路径上的那个模块自动注册,因此 MessageBodyReader 将可用。如果没有,您可以使用客户端明确注册它,例如 client.register(JacksonJaxbJsonProvider.class)。一旦你配置了Jackson支持,那么你可以简单地做一些事情,比如

      That being said, once you have that module on the classpath, is should be automatically registered, so the MessageBodyReader will be available. If not you can register it explicitly with the client, like client.register(JacksonJaxbJsonProvider.class). Once you have the Jackson support configured, then you can simply do something like

      MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);
      

      至于发布/发送数据,您可以再次查看不同的调用.Builder 方法。例如

      As for posting/sending data, you can again look at the different Invocation.Builder methods. For instance

      Invocation.Builder builder = target.request();
      

      如果我们想发布,请查看不同的 发布 方法可用。我们可以使用

      If we want to post, look at the different post methods available. We can use


      • 回复帖子(实体<?>实体) - 我们的请求可能类似于

      • Response post(Entity<?> entity) - Our request might look something like

      Response response = builder.post(Entity.json(myPojo));
      

      你会注意到 实体 。所有 post 方法都接受实体,这就是请求将知道实体主体应该是什么类型的方式,并且客户端将调用approriate MessageBodyWriter 并设置相应的标题

      You'll notice the Entity. All the post methods accept an Entity, and this is how the request will know what type the entity body should be, and the client will invoke the approriate MessageBodyWriter as well as set the appropriate header

      < T> T post(实体<?>实体,Class< T> responseType) - 还有另一个重载,我们可以在其中指定要解组的类型,而不是返回响应。我们可以做到

      <T> T post(Entity<?> entity, Class<T> responseType) - There's another overload, where we can specify the type to unmarshal into, instead of getting back a Response. We could do

      MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
      


      请注意,响应,我们称其 readEntity(类pojoType)方法从实体主体 Response 中读取。这样做的好处是 Response 对象附带了许多我们可以使用的有用信息,比如标题等。就个人而言,我总是得到回复

      Note that with Response, we call its readEntity(Class pojoType) method to read from the Response, the entity body. The advantage of this, is that the Response object comes with a lot of useful information we can use, like headers and such. Personally, I always get the Response

          Response response = builder.get();
          MyPojo pojo = response.readEntity(MyPojo.class);
      

      顺便说一句,对于您展示的特定代码,您很可能希望将其设为 @POST 方法。记住 @GET 主要用于检索数据, PUT 用于更新, POST 用于创建。首次出发时,坚持这是一个很好的经验法则。因此,您可以将方法更改为

      As an aside, for your particular code you are showing, you most likely want to make it a @POST method. Remember @GET is mainly for retrieving data, PUT for updating, and POST for creating. That is a good rule of thumb to stick to, when first starting out. So you might change the method to

      @Path("orders")
      public class OrdersResource  {
      
          @POST
          @Produces(MediaType.APPLICATION_JSON)
          @Consumes({MediaType.APPLICATION_JSON})
          public Response createOrder(@Context UriInfo uriInfo, Order input) {
             Order order = orderService.createOrder(input);
             URI uri = uriInfo.getAbsolutePathBuilder().path(order.getId()).build();
             return Response.create(uri).entity(order).build();
          }
      }
      

      然后你可以做

      WebTarget target = client.target(BASE).path("orders");
      Response response = target.request().accept(...).post(Entity.json(order));
      Order order = response.readEntity(Order.class);
      

      这篇关于接受并返回对象的REST服务。怎么写客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆