Java 接受并返回对象的REST服务。如何编写客户端?

Java 接受并返回对象的REST服务。如何编写客户端?,java,rest,jersey,jersey-client,Java,Rest,Jersey,Jersey Client,我已经声明了两个RESTWeb服务。只返回一个对象的函数。另一个接受一个对象并返回另一个对象。 使用POJO Order.java @XmlRootElement public class Order { private String id; private String description; public Order() { } @XmlElement public String getId() { return id;

我已经声明了两个RESTWeb服务。只返回一个对象的函数。另一个接受一个对象并返回另一个对象。 使用POJO Order.java

@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被定义为

@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服务。客户端代码如下

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();
  }
但我不明白如何调用接受和返回对象的其他服务。 我在网上尝试了不同的解决方案。但对我来说什么都不管用。有些解决方案仅适用于发送对象,有些解决方案仅适用于接受。但没有人能在一次通话中同时做到这两个方面

编辑 正如下面回答中所建议的,我注册了JacksonJaxbJsonProvider.class,但并没有自动转换为Order对象

        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”:“这是第一个顺序”},但获取直接对象会抛出错误
找不到媒体类型=应用程序/json、类型=类shopping.cart.om.Order、genericType=类shopping.cart.om.Order的MessageBodyReader

您应该使用POST或PUT来代替GET

试试这个代码

final Client client = new Client();
    final Order input = new Order();
    input.setId("1");
    input.setDescription("description");
    final Order output = client.resource(
"http://localhost:8080/orders/writeAndIncrementOrder").
            header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON).
            entity(input).post(Order.class);

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

WebTarget=client.target(getBaseURI()).path(“rest”).path(“订单”)

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

target.path(“oneOrder”).request().accept(MediaType.APPLICATION\u JSON.get(String.class)

  • WebTarget.request()
    返回
  • Invocation.Builder.accept(..)
    返回
    Invocation.Builder
  • Invocation.Builder.get()
使用
get(String.class)
所做的是将响应流反序列化为Sting类型的响应。这不是问题,因为JSON本质上只是一个字符串。但是如果您想将其解组到POJO,那么您需要有一个
MessageBodyReader
,它知道如何将JSON解组到POJO类型。Jackson在其依赖项中提供了一个
MessageBodyReader

<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.4.0</version>
</dependency>
至于发布/发送数据,您可以再次查看不同的
Invocation.Builder
方法。比如说

Invocation.Builder builder = target.request();
如果我们想发布,请查看可用的不同方法。我们可以使用

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

    MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);
    
    Response response = builder.post(Entity.json(myPojo));
    
    你会注意到的。所有的
    post
    方法都接受一个
    实体
    ,这就是请求如何知道实体主体应该是什么类型,客户端将调用适当的
    MessageBodyWriter
    并设置适当的头

  • T post(Entity-Entity,Class-responseType)
    -还有另一个重载,我们可以指定要解组的类型,而不是返回
    响应。我们可以做

    MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
    
注意,对于
Response
,我们调用它的
readEntity(类pojoType)
方法来读取
响应
,实体体。这样做的好处是,
响应
对象附带了很多有用的信息,我们可以使用这些信息,比如标题等等。就我个人而言,我总是得到
的回复

    Response response = builder.get();
    MyPojo pojo = response.readEntity(MyPojo.class);
另一方面,对于您正在显示的特定代码,您很可能希望将其作为
@POST
方法。请记住,
@GET
主要用于检索数据,
PUT
用于更新,
POST
用于创建。这是一个很好的经验法则,在刚开始的时候要坚持。因此,您可以将方法更改为

@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);

我用了com.sun.jersey.api.client.client我试过你的建议。但它正在引发异常,原因是:com.sun.jersey.api.client.ClientHandlerException:找不到Java类型、类shopping.cart.om.Order和MIME媒体类型application/json的消息体编写器。看起来像是客户端错误。即使我的服务器停止,我仍然会收到相同的错误。这意味着它甚至没有到达服务器端。请尝试将
com.sun.jersey json 1.8
添加到pom.xml文件中,并将版本设置为实际的jersey版本以获取答案。我终于可以找到工作客户了。我不得不转向maven,因为我被困在罐子的丛林中。目前您的客户机代码是Jersey/JAX-RS 2,但您的web.xml意味着您正在使用Jersey 1。怎么回事?服务器和客户端是同一个项目吗?如果是这样,您可能希望对依赖项进行一些更改。如果您需要这方面的帮助,请显示您的依赖项,并指定是使用Jersey 1还是2。这两个人在同一个项目中合作得不好。即使你只是在客户端使用2,我真的很困惑。我得到的每一个建议都试图修改代码。然后我要加几个罐子。现在,我的客户机和服务器都有许多JAR。我不知道哪些是需要的,哪些是正确的组合。你在使用Maven吗?您想使用哪个版本的Jersey?试试
target2.register(JacksonJaxbJsonProvider.class)
我没有使用Maven。我正在Eclipse中创建项目。这两个项目都是不同的项目。感谢您在概念层面给出的非常详细的回复。我将花一些时间来理解上述概念,并将带着我的结果回来。谢谢。请注意,上面是针对Jersey/JAX-R的