如何在POST请求期间获取不同资源的JAX-RS @Path?

18

我有两个REST类用于一个简单的Web服务(Jersey和GlassFish),涉及用户资源 - 一个用于操作所有用户(例如,@ POST),另一个用于单个用户(例如,@ GET,@ PUT,@ DELETE)。它们位于:

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

分别地。当向 AllUsersResource 进行 POST 请求时,我希望返回新用户的位置(通过 Response.created(uri).build()),例如:

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

我的问题是如何实现这一点。AllUsersResource注入了@Context UriInfo uriInfo,但这不会为OneUserResource提供@Path信息,只提供当前调用的信息("users")。最终我让它工作的方法是简单地使用反射,但我担心这种方法过于脆弱和不干净:

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]+}"。 - absmiths
4个回答

15

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

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

1
这将返回http://localhost:8080/project/users/152,而不是所需的http://localhost:8080/project/user/152 - brain storm

10

我发现了一些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响应,则仍然没有办法:( - curioustechizen

5

通过严格遵循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;
}

1
从JAX-RS 2.0开始,最正确的方法(据我所知)是使用构建器方法,如下所示:
    String uri = uriInfo.getBaseUriBuilder()
      .path(ODataV4Endpoint.class)
      .path(ODataV4Endpoint.class, "serviceEndpointJSONCatalog")
      .resolveTemplate("endpointId", endpointId).build().toString();

FYI,我需要在我的情况下调用两次路径,一次是类上的路径注释,第二次是方法注释。我怀疑调用方法会同时完成两个注释,但实际上并不是这样。
端点serviceEndpointJSONCatalog上的路径注释声明了一个参数,如 'endpoint/{endpointId}',因此需要调用resolveTemplate。否则,您只需调用path(Class cl,String method)。
在我的情况下,我创建了一个构建器和符号方式来引用方法,以便编译器/运行时可以检查它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接