接受并返回对象的REST服务。 怎么写客户端?
我已经声明了两个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 }
Web服务定义为
@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”:“这是第一顺序”}但是获取直接对象抛出错误MessageBodyReader未找到媒体类型= application / json,type = class shopping .cart.om.Order,genericType = class shopping.cart.om.Order。
如果您花一点时间来理解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
。 Jackson在其jackson-jaxrs-json-provider
依赖项中提供了MessageBodyReader
com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider 2.4.0
大多数实现都会为这个模块提供一个包装器,比如Jersey的jersey-media-json-jackson
或者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
,这就是请求将如何知道实体主体应该是什么类型,并且客户端将调用approriateMessageBodyWriter
以及设置适当的头 -
– 还有另一个重载,我们可以指定要解组的类型,而不是获取T post(Entity> entity, Class responseType) Response
。 我们能做到MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
请注意,使用Response
,我们将其readEntity(Class pojoType)
方法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);
您应该使用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);