Как я могу получить JAX-RS @Path другого ресурса во время POST? - PullRequest
13 голосов
/ 23 февраля 2012

У меня есть два класса REST для простого веб-сервиса (Jersey и GlassFish), который включает пользовательские ресурсы - один для работы со всеми пользователями (например, фабрика для @POSTing), а другой для отдельных пользователей (например, @GET, @ PUT, @DELETE). Они находятся по адресу:

@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, но это не дает мне информацию @Path для OneUserResource, а только информацию о текущем вызове («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;

Любая помощь будет потрясающей!

Ответы [ 4 ]

14 голосов
/ 13 декабря 2012

Вы можете использовать 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();
}
9 голосов
/ 27 февраля 2012

Я нашел пару методов 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();
5 голосов
/ 26 июня 2012

С помощью строгой концепции 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;
}
0 голосов
/ 16 августа 2018

Начиная с JAX-RS 2.0, наиболее правильный способ (насколько я знаю) - использовать метод построителя следующим образом:

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

К вашему сведению, мне нужно дважды вызывать path в моем случае, один раз для аннотации пути к классу, и второй раз для аннотации метода.Я подозревал, что вызов метода будет делать и то, и другое, но это не так.

Аннотация Path в конечной точке serviceEndpointJSONCatalog объявляет параметр, например, так: 'endpoint / {endpointId}', поэтому вызов resolTemplateнеобходимо.В противном случае вы просто вызвали бы путь (класс cl, метод String).

В моем случае я создал конструктор и символический способ ссылки на методы, чтобы компилятор / среда выполнения могли их проверять.

...