【问题标题】:How do I get the JAX-RS @Path of a different resource during a POST?如何在 POST 期间获取不同资源的 JAX-RS @Path?
【发布时间】:2012-03-14 03:49:07
【问题描述】:

我有两个用于涉及用户资源的简单 Web 服务(Jersey 和 GlassFish)的 REST 类 - 一个用于对所有用户进行操作(例如,@POSTing 的工厂),另一个用于单个用户(例如,@GET、@放,@删除)。他们在:

@Stateless @Path("users") public class AllUsersResource {...}
@Stateless @Path("user") public class OneUserResource {...}

分别。发布到 AllUsersResource 时,我想返回新用户的位置(通过 Response.created(uri).build()),例如,

http://localhost:8080/.../user/152

我的问题是如何做到这一点。 AllUsersResource 注入@Context UriInfo uriInfo,但这并没有让我获得OneUserResource 的@Path 信息,只有当前调用(“用户”)的信息。我最终让它工作的方式是简单地使用反射,但我担心它是脆弱和不干净的:

OneUserResource.class.getAnnotation(Path.class).value();

搜索 StackOverflow 我发现尝试的唯一其他方法如下,但均未成功:

  • com.sun.jersey.api.core.ResourceContext
  • javax.ws.rs.core.UriInfo.getMatchedResources()
  • @javax.inject.Inject OneUserResource oneUserRes;

任何帮助都会很棒!

【问题讨论】:

  • 这个老问题今天与我有关。直接使用路径注释时要小心,因为其中可能存在表达式或路径参数,它们不会直接转换为路径,例如,“service/{username}”、“service/{empId: [0-9]+}” .

标签: java rest path jersey jax-rs


【解决方案1】:

我发现了几个 javax.ws.rs.core.UriBuilder 方法可以解决问题,我想分享这些方法以防其他人有这个问题。它们是:UriBuilder.fromResource(OneUserResource.class) 和 javax.ws.rs.core.UriBuilder.path(Class)。我在一次通话中使用了后者:

URI newUserUri = uriInfo.getBaseUriBuilder().path(OneUserResource.class).path("/" + user.getId()).build();
return Response.created(newUserUri).build();

【讨论】:

  • 这两种方法的问题是它们都需要 root 资源类才能工作。如果您从子资源中使用它们(IllegalArgumentException 被抛出),它们将不起作用。因此,如果您使用了处理 POST 请求的子资源;并且您想返回带有Location 标头的201,您仍然不走运:(
【解决方案2】:

通过严格的 REST 概念,您可以将其作为一个根资源

@POST   /users        -> CREATE a single user
@GET    /users        -> READ all users
@PUT    /users        -> UPDATE (REPLACE) all users @@?
@DELETE /users        -> DELETE all users @@?

@POST   /users/{id}   -> CREATE a single user's some other child; @@?
@GET    /users/{id}   -> READ a single user
@PUT    /users/{id}   -> UPDATE a single user
@DELETE /users/{id}   -> DELETE a single user
@Path("/users")
@Stateless
public class UsersResouce {

    // /users
    @POST
    @Consumes({MediaType.APPLICATION-XML, MediaType.APPLICATION-JSON})
    public Response createUser(final User user) {
        // persist the user here
        return Response.created("/" + user.getId()).build();
    }

    // /users
    @GET
    @Produces({MediaType.APPLICATION-XML, MediaType.APPLICATION-JSON})
    public Response readUsers() {
        //return all users
    }

    // /users/{id}
    @GET
    @Path("/{user_id: \\d+}")
    @Produces({MediaType.APPLICATION-XML, MediaType.APPLICATION-JSON})
    public Response readUser(
        @PathParam("user_id") final Long userId) {

        final User persisted = userBean.find(userId);

        if (persisted == null) {
            return Response.status(Status.NOT_FOUND).build();
        }

        return Response.ok().entity(persisted).build();
    }

    // /users/{id}
    @Consumes({MediaType.APPLICATION-XML, MediaType.APPLICATION-JSON})
    @PUT
    @Path("/{user_id: \\d+}")
    public Response updateUser(
        @PathParam("user_id") final Long userId,
        final User mergeable) {

        final User persisted = userBean.find(userId);

        if (persisted == null) {
            userBean.persist(mergeable);
        } else {
            persist.setName(mergeable.getName());
            userBean.merge(persisted);
        }

        return Response.status(Status.NO_CONTENT).build();
    }

    // /users/{id}
    @DELETE
    @Path("/{user_id: \\d+}")
    public Response deleteUser(
        @PathParam("user_id") final Long userId) {

        userBean.delete(userId);

        return Response.status(Status.NO_CONTENT).build();
    }

    @EJB
    private UserBean userBean;
}

【讨论】:

    【解决方案3】:

    您可以使用 UriBuilder.fromresource(),但这仅在提供的 Resource 类是根资源时才有效(这在 javadocs 中有明确提及)。即使您在子资源类中,我也找到了实现此目的的方法:

    @POST
    @Consumes({MediaType.APPLICATION-XML, MediaType.APPLICATION-JSON})
    public Response createUser(final User user, @Context UriInfo uriInfo) {
        // persist the user here
        URI uri = uriInfo.getAbsolutePathBuilder().path(user.getId()).build();
        return Response.created(uri).build();
    }
    

    【讨论】:

    • 这将返回 http://localhost:8080/project/users/152 而不是 http://localhost:8080/project/user/152 而后者是 SO 所需要的
    【解决方案4】:

    从 JAX-RS 2.0 开始,最正确的方法(据我所知)是使用 builder 方法,如下所示:

        String uri = uriInfo.getBaseUriBuilder()
          .path(ODataV4Endpoint.class)
          .path(ODataV4Endpoint.class, "serviceEndpointJSONCatalog")
          .resolveTemplate("endpointId", endpointId).build().toString();
    

    仅供参考,在我的情况下,我需要调用两次路径,一次用于类上的路径注释,第二次用于方法上的注释。我怀疑对该方法的调用会同时执行这两种操作,但事实并非如此。

    端点 serviceEndpointJSONCatalog 上的 Path 注释声明了一个参数,如下所示:'endpoint/{endpointId}',因此需要调用 resolveTemplate。否则你只会调用 path(Class cl, String method)。

    在我的例子中,我创建了一个构建器和一个符号方式来引用这些方法,以便编译器/运行时可以检查它们。

    【讨论】:

      猜你喜欢
      • 2010-12-21
      • 1970-01-01
      • 2013-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多