我已经宣布了两个REST Web服务。一个简单地返回一个对象。和其他接受一个对象并返回另一个对象。 使用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":"这是第一个订单&#34但是获得直接对象会引发错误 找不到媒体类型= application / json的typeBodyReader,type = class shopping.cart.om.Order,genericType = class shopping.cart.om.Order。
答案 0 :(得分:14)
如果您花一点时间来了解WebTarget
API,以及通过调用WebTarget
方法返回的不同类型,您应该更好地了解如何打电话。这可能有点令人困惑,因为几乎所有示例都使用方法链接,因为它是一种非常方便的方式,但是这样做,您会错过创建和发送请求所涉及的所有实际类。让我们分解一下
WebTarget target = client.target(getBaseURI()).path("rest").path("orders");
WebTarget.path()
只返回WebTarget
。那里没什么有趣的。
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)
您对get(String.class)
所做的是说应该将响应流反序列化为Sting类型响应。这不是问题,因为JSON本质上只是一个String。但是如果你想将它解组为POJO,那么你需要知道如何将JSON解组为POJO类型的MessageBodyReader
。杰克逊提供了MessageBodyReader
jackson-jaxrs-json-provider
依赖
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
大多数实现都会为此模块提供一个包装器,例如Jersey的jersey-media-json-jackson
或Resteasy的resteasy-jackson-provider
。但他们仍在使用基础jackson-jaxrs-json-provider
。
话虽这么说,一旦你在类路径上拥有该模块,应自动注册,因此MessageBodyReader
将可用。如果没有,您可以明确地向客户注册,例如client.register(JacksonJaxbJsonProvider.class)
。一旦配置了Jackson支持,那么您可以简单地执行类似
MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);
对于发布/发送数据,您可以再次查看不同的Invocation.Builder
方法。例如
Invocation.Builder builder = target.request();
如果我们想发布,请查看可用的不同post
方法。我们可以使用
Response post(Entity<?> entity)
- 我们的请求可能类似于
Response response = builder.post(Entity.json(myPojo));
您会注意到Entity
。所有post
方法都接受Entity
,这就是请求将知道实体主体应该是什么类型的方式,客户端将调用适当的MessageBodyWriter
以及设置适当的头
<T> T post(Entity<?> entity, Class<T> responseType)
- 还有另一个重载,我们可以指定要解组的类型,而不是取回Response
。我们可以做到
MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
请注意,对于Response
,我们将其readEntity(Class pojoType)
方法称为实体主体Response
。这样做的好处是,Response
对象带有许多我们可以使用的有用信息,比如标题等。就个人而言,我总是得到Response
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);
答案 1 :(得分:4)
你应该使用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);