bra*_*orm 4 jax-rs put jersey java-ee
我正在阅读oracle docs中提供的Jersey Sample中的存储服务示例示例.
我只是无法理解JAX-RS运行时如何解决这个PUT请求?
curl -X PUT http://127.0.0.1:9998/storage/containers/quotes
Run Code Online (Sandbox Code Playgroud)
这是与此请求对应的代码段(取自上面的链接).
@Path("/containers")
@Produces("application/xml")
public class ContainersResource {
@Context UriInfo uriInfo;
@Context Request request;
@Path("{container}")
public ContainerResource getContainerResource(@PathParam("container") String container) {
return new ContainerResource(uriInfo, request, container);
}
@GET
public Containers getContainers() {
System.out.println("GET CONTAINERS");
return MemoryStore.MS.getContainers();
}
}
Run Code Online (Sandbox Code Playgroud)
但是你可以注意到,没有办法@PUT annotation.但是需要这种getContainerResource方法/containers/{container}.在此方法中,ContainerResource返回一个新实例.我不确定如何处理上述PUT请求.请解释.
这是ContainerResource class:
@Produces("application/xml")
public class ContainerResource {
@Context UriInfo uriInfo;
@Context Request request;
String container;
ContainerResource(UriInfo uriInfo, Request request, String container) {
this.uriInfo = uriInfo;
this.request = request;
this.container = container;
}
@GET
public Container getContainer(@QueryParam("search") String search) {
System.out.println("GET CONTAINER " + container + ", search = " + search);
Container c = MemoryStore.MS.getContainer(container);
if (c == null)
throw new NotFoundException("Container not found");
if (search != null) {
c = c.clone();
Iterator<Item> i = c.getItem().iterator();
byte[] searchBytes = search.getBytes();
while (i.hasNext()) {
if (!match(searchBytes, container, i.next().getName()))
i.remove();
}
}
return c;
}
@PUT
public Response putContainer() {
System.out.println("PUT CONTAINER " + container);
URI uri = uriInfo.getAbsolutePath();
Container c = new Container(container, uri.toString());
Response r;
if (!MemoryStore.MS.hasContainer(c)) {
r = Response.created(uri).build();
} else {
r = Response.noContent().build();
}
MemoryStore.MS.createContainer(c);
return r;
}
@DELETE
public void deleteContainer() {
System.out.println("DELETE CONTAINER " + container);
Container c = MemoryStore.MS.deleteContainer(container);
if (c == null)
throw new NotFoundException("Container not found");
}
@Path("{item: .+}")
public ItemResource getItemResource(@PathParam("item") String item) {
return new ItemResource(uriInfo, request, container, item);
}
private boolean match(byte[] search, String container, String item) {
byte[] b = MemoryStore.MS.getItemData(container, item);
OUTER: for (int i = 0; i < b.length - search.length + 1; i++) {
for (int j = 0; j < search.length; j++) {
if (b[i + j] != search[j])
continue OUTER;
}
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个称为子资源定位器的文档功能:https: //jersey.java.net/documentation/latest/jaxrs-resources.html
@Path("{container}")
public ContainerResource getContainerResource(@PathParam("container") String container) {
return new ContainerResource(uriInfo, request, container);
}
Run Code Online (Sandbox Code Playgroud)
上面的@Path注释将ContainerResource标识为子资源.请注意,ContainerResource确实具有正在调用的带注释的PUT方法.如果您需要进一步解释,我可以尝试扩展此答案.
更新
这不容易解释,但这里有一个解释它...
让我们通过查看您的类支持的各种URL开始解释这一点.ContainersResource类实现的唯一端点如下:
GET /containers/
Run Code Online (Sandbox Code Playgroud)
此端点是顶级资源的一部分.显然它返回容器的集合/列表.
现在如果我们想要一个端点来获取id的特定容器呢?正常的REST端点会在集合上使用GET操作公开端点,然后将id作为路径参数(PathParam),因此对于ID为27的容器,调用可能如下所示:
GET /containers/27/
Run Code Online (Sandbox Code Playgroud)
这样做的一个解决方案如下:
@Path("/containers")
@Produces("application/xml")
public class ContainersResource {
@Context UriInfo uriInfo;
@Context Request request;
@GET
public Containers getContainers() {
System.out.println("GET CONTAINERS");
return MemoryStore.MS.getContainers();
}
//
// This is a solution WITHOUT sub-resource...
// Note that the Path annotation is same as you have it, but
// now the HTTP method annotation is provided. Also, the
// method returns Container instead of ContainerResource
//
@Path("{container}")
@GET
public Container getContainerResource(@PathParam("container") String container) {
// Go to memory store and get specific container...
Container x = findContainer(container);
return x;
}
//
// Again, without sub-resource, we can define PUT method
// on specific container id and again define the path param
//
@Path("{container}")
@PUT
public Response putContainer(@PathParam("container") String container) {
// Process payload to build container, put into memory store
Response r = putContainer(container, ...);
return r;
}
}
Run Code Online (Sandbox Code Playgroud)
不使用子资源导致我们必须将多个GET,PUT,POST,DELETE方法放入同一个类中,因为我们将方法从较低级别的资源提升到最顶层的资源类.它还使我们必须多次为容器ID定义路径参数.这只是两个级别的资源(容器集合和特定容器)所以它看起来并不太糟糕,但随着我们的路径变得更深入呢?容器具有项目,因此完全可访问的API可以实现端点,该端点允许您仅检索特定集合中的项目,甚至是集合中的特定项目.这些调用分别如下所示:
GET /containers/27/items/ (to get the items collection)
GET /containers/27/items/9/ (to get specific item from collection)
Run Code Online (Sandbox Code Playgroud)
所以现在,我们的父资源需要定义4个单独的GET方法.
为了避免在同一个类中使用多个GET/POST/PUT/DELETE方法,我们仍然可以将这些方法分解为4个不同的类,每个类在类上都有唯一的Path注释,但是如果路径中的某些术语(如"容器")需要重命名,那么我们将不得不在4个地方而不是一个地方更新代码.此外,必须在每个方法上定义沿路径的所有路径参数.
为了说明这一点,请考虑您提供的使用子资源的ContainersResource类:
@Path("/containers")
@Produces("application/xml")
public class ContainersResource {
@Context UriInfo uriInfo;
@Context Request request;
@Path("{container}")
public ContainerResource getContainerResource(@PathParam("container") String container) {
return new ContainerResource(uriInfo, request, container);
}
}
Run Code Online (Sandbox Code Playgroud)
getContainerResource方法声明存在由path参数"container"标识的子资源.如果我们不使用子资源,可以直接在ContainerResource类中实现,如下所示:
@Path("containers/{container}")
@Produces("application/xml")
public class ContainerResource {
@GET
public Container getContainer(
@PathParam("container") String container,
@QueryParam("search") String search) {
System.out.println("GET CONTAINER " + container + ", search = " + search);
Container c = MemoryStore.MS.getContainer(container);
// do work
return c;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我必须将Path注释添加到类中以定义端点位置以及存在路径参数的事实.另外,我必须向GET方法添加一个PathParam参数(并且必须将它添加到我的其他方法中)以了解容器值是什么.
为了进一步证明这一点,请考虑我们是否在不使用子资源的情况下实现ContainerItemsResource:
@Path("containers/{container}/items")
@Produces("application/xml")
public class ContainerItemsResource {
@GET
public ContainerItems getContainerItems(
@PathParam("container") String container) {
Container c = MemoryStore.MS.getContainer(container);
return c.getItems();
}
}
Run Code Online (Sandbox Code Playgroud)
和ContainerItemResource
@Path("containers/{container}/items/{item}")
@Produces("application/xml")
public class ContainerItemResource {
@GET
public ContainerItem getContainerItem(
@PathParam("container") String container,
@PathParam("item" String item) {
Container c = MemoryStore.MS.getContainer(container);
return c.getItems();
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们再次重复完整的Path并且必须在每个方法上重新定义容器路径参数.
子资源提供了一种优雅的解决方案:(1)允许路径中的每个级别使用单个GET/PUT/POST/DELETE方法拥有自己的类,(2)不需要在多个位置重新定义路径中的级别,并且( 3)不需要在每个方法上重新定义查询参数.以下是使用子资源方法的四个资源文件(仅提供GET方法用于说明):
@Path("/containers")
@Produces("application/xml")
public class ContainersResource {
@Context UriInfo uriInfo;
@Context Request request;
// Define sub-resource for specific container
@Path("{container}")
public ContainerResource getContainerResource(@PathParam("container") String container) {
return new ContainerResource(container);
}
// Provide @GET, @PUT, @POST, @DELETE to get collection of containers
@GET
public Containers getContainers() {
return MemoryStore.MS.getContainers();
}
}
@Produces("application/xml")
public class ContainerResource {
@Context UriInfo uriInfo;
@Context Request request;
String container;
// Constructor allowing it to be used as sub-resource
ContainerResource(String container) {
this.container = container;
}
// Define sub-resource for items collection
@Path("items")
public ContainerItemsResource getContainerItemsResource() {
return new ContainerItemsResource(container);
}
// Provide @GET, @PUT, @POST, @DELETE to get specific container
// Notice that path params are not redefined...
@GET
public Container getContainer() {
Container c = MemoryStore.MS.getContainer(container);
return c;
}
}
@Produces("application/xml")
public class ContainerItemsResource {
@Context UriInfo uriInfo;
@Context Request request;
String container;
// Constructor allowing it to be used as sub-resource
ContainerItemsResource(String container) {
this.container = container;
}
// Define sub-resource for specific item
@Path("{item}")
public ContainerItemsResource getContainerItemsResource(@PathParam("container") String container, @PathParam("item") String item) {
return new ContainerItemResource(container, item);
}
// Provide @GET, @PUT, @POST, @DELETE to get specific container items collection
// Notice that path params are not redefined...
@GET
public ContainerItems getContainerItems() {
Container c = MemoryStore.MS.getContainer(container);
return c.getItems();
}
}
@Produces("application/xml")
public class ContainerItemResource {
@Context UriInfo uriInfo;
@Context Request request;
String container;
String item;
// Constructor allowing it to be used as sub-resource
ContainerItemResource(String container, String item) {
this.container = container;
this.item = item;
}
// Provide @GET, @PUT, @POST, @DELETE to get specific container item
// Notice that path params are not redefined...
@GET
public ContainerItem getContainerItem() {
Container c = MemoryStore.MS.getContainer(container);
return c.getItem(item);
}
}
Run Code Online (Sandbox Code Playgroud)
通过使用子资源提供这个四级深度资源的示例,希望它能澄清您的代码正在做什么.子资源方法在整个资源中消除了重复的路径和路径参数定义,使代码更易于维护,并且(意见)更易于阅读.
| 归档时间: |
|
| 查看次数: |
1211 次 |
| 最近记录: |