gpt4 book ai didi

jakarta-ee - JAX-RS 运行时如何处理本示例中使用子资源的 PUT 请求?

转载 作者:行者123 更新时间:2023-12-05 01:02:30 25 4
gpt4 key购买 nike

我正在阅读 oracle docs. 中提供的 Jersey Sample 中的存储服务示例示例

我只是无法理解 JAX-RS 运行时如何解决这个 PUT 请求?

curl -X PUT http://127.0.0.1:9998/storage/containers/quotes

这是与此请求对应的代码片段(取自上述链接)。
@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();
}
}

但是正如您所注意到的,没有方法可以使用 @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;
}
}

最佳答案

这是一个称为子资源定位器的记录功能:https://jersey.java.net/documentation/latest/jaxrs-resources.html

@Path("{container}")
public ContainerResource getContainerResource(@PathParam("container") String container) {
return new ContainerResource(uriInfo, request, container);
}

上面的@Path 注释将 ContainerResource 标识为子资源。请注意,ContainerResource 确实有一个正在调用的带注释的 PUT 方法。如果您需要进一步解释,我可以尝试扩展此答案。

更新

这并不容易解释,但这里有一个解释它的尝试......

让我们通过查看您的类支持的各种 URL 来开始解释这一点。 ContainersResource 类实现的唯一端点如下:
GET /containers/

此端点是顶级资源的一部分。显然它返回容器的集合/列表。

现在如果我们想要一个端点通过 id 获取特定的容器怎么办?正常的 REST 端点将使用集合上的 GET 操作公开端点,然后将 id 作为路径参数 (PathParam),因此对于 id 为 27 的容器,调用可能如下所示:
GET /containers/27/

执行此操作的一种解决方案如下:
@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;
}

}

不使用子资源导致我们必须将多个 GET、PUT、POST、DELETE 方法放入同一个类中,因为我们将方法从较低级别的资源提升到最顶层的资源类。它还导致我们必须多次定义容器 id 的路径参数。这只是 2 个级别的资源(容器集合和特定容器),所以看起来还不错,但是随着我们的路径越来越深呢?容器具有项目,因此完全可访问的 API 可以实现一个端点,允许您仅检索特定集合中的项目,甚至是集合中的特定项目。这些调用分别如下所示:
GET /containers/27/items/ (to get the items collection)
GET /containers/27/items/9/ (to get specific item from collection)

所以现在,我们的父资源需要定义 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);
}

}

getContainerResource 方法声明有一个由路径参数“容器”标识的子资源。如果我们不使用子资源,这可以直接在 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;
}
}

请注意,我必须向类添加 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();
}
}

和 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();
}
}

在这里,我们再次重复完整路径,并且必须在每个方法上重新定义容器路径参数。

子资源提供了一种优雅的解决方案,它 (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);
}

}

通过提供这个使用子资源的四级深度资源示例,希望它能阐明您的代码在做什么。子资源方法消除了整个资源中重复的路径和路径参数定义,使代码更易于维护和(意见)更易于阅读。

关于jakarta-ee - JAX-RS 运行时如何处理本示例中使用子资源的 PUT 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26270706/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com