Как сопоставить суффикс пути с параметром запроса, используя Java Jersey?

#java #rest #jersey

#java #rest #джерси

Вопрос:

Справочная информация: некоторое время назад мы создали RESTful API с использованием Jersey, где мы сопоставляем uri /items.json с массивом идентификаторов json, а /items/{id}.json — с объектом json одного элемента. Теперь мы хотим создать список с некоторыми метаданными для каждого элемента и хотели бы использовать селектор типа /items.data.json , аналогичный apache sling.

Пока что: я просто расширил UriConnegFilter для анализа uri на наличие дополнительных суффиксов, что-то вроде этого:

 public class UriSelectorFilter extends UriConnegFilter {
protected List<String> selectors; // this list is populated in the constructor

    public ContainerRequest filter(ContainerRequest request) {
        super.filter(request);
        // search for suffix in last path segment, see http://java.net/projects/jersey/sources/svn/content/trunk/jersey/jersey-server/src/main/java/com/sun/jersey/api/container/filter/UriConnegFilter.java?rev=5034

        final String[] suffixes = segment.getPath().split("\.");
        for (int i = suffixes.length - 1; i >= 1; i--) {
            final String suffix = suffixes[i];
            if(selectors.contains(suffix)) {
                request.getQueryParameters().putSingle("selector", suffix);

                final int index = path.lastIndexOf('.'   suffix);
                path = new StringBuilder(path).delete(index, index   suffix.length()   1).toString();
                suffixes[i] = "";
            }
        }

        if (length != path.length()) {
            request.setUris(
                    request.getBaseUri(),
                    request.getRequestUriBuilder().replacePath(path).build());
        }
        return request;
    }
}
  

Этот фильтр работает идеально, он находит часть селектора моего uri и добавляет параметр запроса к объекту запроса. Но в моем ресурсе я добавил атрибут @QueryParam, который заполняется только значением по умолчанию, а не добавленным значением запроса:

 @GET
@Produces(MediaType.APPLICATION_JSON)
public Response getItemsJSON(@DefaultValue("id") @QueryParam("selector") String selector) {
    // query param is not filled with the selector that was found in the UriSelectorFilter
}
  

У кого-нибудь есть предложения, как я могу предоставить моему ресурсу селектор, который был обнаружен? Есть ли способ лучше, чем использование параметра запроса? (Примечание: если я добавлю запрос к своему URL-адресу типа ‘?selector =something’, то атрибут будет заполнен правильно.)

Любая помощь очень ценится.

Ответ №1:

Вам нужен другой аргумент, который снабжен аннотацией с помощью @PathParam , и вам нужно указать в вашей @Path аннотации (к методу или классу), как связать эти биты вместе. Например, для работы с таким путем, как /items/foobar42/data.json вы могли бы сделать это:

 @GET
@Path("/items/{item}/data.json")
@Produces(MediaType.APPLICATION_JSON)
public Response getItemsJSON(@PathParam("item") String itemId,
        @DefaultValue("id") @QueryParam("selector") String selector) {
    // Now you've got an itemId and a possible selector...
}
  

Пытаюсь выполнить все сопоставление с фильтром… это кажется мне сложным, учитывая, что вместо этого есть хороший декларативный способ сделать это. Вы даже можете указать регулярное выражение в @Path разделе, позволяющем сопоставлять более сложные переменные; Я делаю это в своем собственном коде, чтобы создать метод, который может обслуживать целую иерархическую файловую систему.

(Обратите внимание, что { связанный } элемент в @Path должен соответствовать имени в @PathParam аннотации, и при необходимости вы можете сопоставить несколько элементов из пути; просто используйте несколько @PathParam аргументов с аннотациями.)