Как настроить приложение JAX-RS, используя только аннотации (без web.xml)?

80

Можно ли настроить приложение JAX-RS, используя только аннотации? (с использованием Servlet 3.0 и JAX-RS Jersey 1.1.0)

Я пытался, но безуспешно. Использование некоторых web.xmlкажется необходимым.


Конфигурация A (работает, но имеет конфигурацию web.xml)

web.xml

   ...
   <servlet>
      <servlet-name>org.foo.rest.MyApplication</servlet-name>
   </servlet>
   <servlet-mapping>
       <servlet-name>org.foo.rest.MyApplication</servlet-name>
       <url-pattern>/*</url-pattern>
   </servlet-mapping>
   ...

Ява

@ApplicationPath("/")
public class MyApplication extends Application {
    ...
}

Конфигурация B (не работает, выбрано исключение)

@ApplicationPath("/")
@WebServlet("/*") // <-- 
public class MyApplication extends Application {
    ...
}

Последний, похоже, настаивает на том, что приложение будет подклассом сервлета (исключение не оставляет никаких догадок)

java.lang.ClassCastException: org.foo.rest.MyApplication cannot be cast to javax.servlet.Servlet

Вопросов

  1. Почему определение web.xml работает, а аннотация - нет? Какая разница?

  2. Есть ли способ заставить это работать, например, иметь приложение JAX-RS без web.xml?

Эран Медан
источник
1
Если вы можете попробовать с NetBeans, есть мастер для создания веб-служб RESTFul. Похоже, что вы пытаетесь сделать то же, что и этот мастер в версии 6.8. Я использую версию 7.0.1, и новый подход проще, но для этой цели используется единственный сервлет, то есть com.sun.jersey.spi.container.servlet.ServletContainer, но он определен в web.xml
perissf

Ответы:

168

** ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ ЕСЛИ ВЫ ИСПОЛЬЗУЕТЕ TOMCAT ИЛИ JETTY! **

Принятый ответ делает работу, но только если веб - приложение развернуто на сервер приложений , как Glassfish или Wildfly, и , возможно , сервлет с ЭЭ расширениями как TomEE. Он не работает со стандартными контейнерами сервлетов, такими как Tomcat, и я уверен, что большинство людей, ищущих здесь решение, захотят использовать.

Если вы используете стандартную установку Tomcat (или какой-либо другой контейнер сервлетов), вам необходимо включить реализацию REST, поскольку Tomcat не поставляется с ней. Если вы используете Maven, добавьте это в dependenciesраздел:

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.bundles</groupId>
    <artifactId>jaxrs-ri</artifactId>
    <version>2.13</version>
  </dependency>
  ...
</dependencies>

Затем просто добавьте в свой проект класс конфигурации приложения. Если у вас нет каких-либо особых требований к конфигурации, кроме установки пути контекста для остальных сервисов, класс может быть пустым. После добавления этого класса вам не нужно ничего настраивать web.xml(или иметь его вообще):

package com.domain.mypackage;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest") // set the path to REST web services
public class ApplicationConfig extends Application {}

После этого объявление ваших веб-сервисов станет простым с использованием стандартных аннотаций JAX-RS в ваших классах Java:

package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;

// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
@Path("calc/1.0")
public class CalculatorV1_0 {
  @GET
  @Consumes("text/plain")
  @Produces("text/plain")
  @Path("addTwoNumbers")
  public String add(@MatrixParam("firstNumber") int n1, @MatrixParam("secondNumber") int n2) {
    return String.valueOf(n1 + n2);
  }
}

Это должно быть все, что вам нужно. Если ваша установка Tomcat выполняется локально на порту 8080 и вы развертываете свой WAR-файл в контексте myContext, переходя к ...

http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3

... должен дать ожидаемый результат (5).

Элвин Томпсон
источник
6
@JavaDude - вам необходимо настроить Maven для создания файла WAR, даже если его web.xmlнет. В вашем pom.xml, в разделе «сборки> плагин», добавьте (если уже не существует): <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>2.3</version><configuration><failOnMissingWebXml>false</failOnMissingWebXml></configuration></plugin>.
Элвин Томпсон
6
@JavaDude - важная часть - это <failOnMissingWebXml>false</fai‌​lOnMissingWebXml>опция.
Элвин Томпсон
3
@JavaDude - Если это не так, вы, вероятно, не создали класс, который расширяется, Applicationи не добавляли @ApplicationPathк нему аннотацию. Класс может быть пустым, но он должен быть там.
Элвин Томпсон
3
Достаточно только добавить jersey-container-servlet, не растягивая всю jaxrs-riзависимость. Например, в моем случае это был 'org.glassfish.jersey.core:jersey-server:2.18'+ 'org.glassfish.jersey.containers:jersey-container-servlet:2.18'.
leveluptor
3
Поскольку вопрос явно помечен тегом «java-ee», я не понимаю, что такое беспорядок в предоставлении и голосовании за ответ, НЕ относящийся к среде jee. -1
Ян Галински
51

Кажется, все, что мне нужно было сделать, это (Servlet 3.0 и выше)

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/*")
public class MyApplication extends Application {
    ...
}

И никакая конфигурация web.xml, по-видимому, не нужна (пробовал на Tomcat 7)

Эран Медан
источник
1
Не понимаете, как это работает, вы можете использовать только аннотацию без какой-либо другой настройки? Я пробовал вот так, но все еще не работает ...
Филипе
2
@Filipe: Я предполагаю, что вы используете Tomcat или другой контейнер сервлетов. На самом деле это не работает с контейнерами сервлетов, такими как Tomcat - это работает только с серверами приложений, такими как Glassfish или Wildfly, и, возможно, TomEE. Если вы используете Tomcat, см. Мой (поздний) ответ ниже.
Элвин Томпсон
8
Этот ответ НЕ работает для Tomcat или Jetty! Пожалуйста, посмотрите мой ответ, чтобы заставить вещи работать в этих (и других) контейнерах сервлетов.
Элвин Томпсон
1
В зависимости от реализации, вы действительно нуждаетесь в web.xml, хотя пустой один будет достаточно. См. Docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/…
Бенджамин Маурер
Это работает в WebSphere Liberty, но не в WebSphere 8.x и 9.0 Classic.
Архимед
15

В главе 2 спецификации JAX-RS: Java ™ API для веб-служб RESTful описывается процесс публикации приложения JAX-RS в среде сервлетов (раздел 2.3.2 Сервлет в спецификации).

Обратите внимание, что рекомендуется только среда Servlet 3 (раздел 2.3.2 Сервлет, стр. 6):

РЕКОМЕНДУЕТСЯ, чтобы реализации поддерживали механизм подключаемости фреймворка Servlet 3, чтобы обеспечить переносимость между контейнерами и использовать средства сканирования классов, предоставляемые контейнером.

Короче говоря, если вы хотите использовать подход no-web.xml, это возможно с помощью специальной реализации javax.ws.rs.core.Application, которая регистрирует ресурсы службы RESTful с помощью аннотации javax.ws.rs.ApplicationPath .

@ApplicationPath("/rest")

Хотя вы спрашивали конкретно о Джерси, вы также можете прочитать статью « Реализация сервисов RESTful с JAX-RS и WebSphere 8.5 Liberty Profile», в которой я описал процесс публикации no-web.xml для WebSphere Liberty Profile (с Apache Wink как реализацию JAX-RS).

Яцек Ласковски
источник
1
Спасибо! У меня есть еще один вопрос, который сводит меня с ума, есть ли способ сохранить путь в корне (например, @ApplicationPath ("/ *")) и при этом обслуживать JSP, используя только аннотации? (хотя даже с конфигурацией web.xml я не мог этого сделать) - вопрос здесь: stackoverflow.com/questions/10874188/… , поскольку вы, кажется, хорошо знаете JAX-RS, не могли бы вы взглянуть? :) возможно, вы увидите, что мне не хватает ... спасибо!
Эран Медан
Я не знаю. Внутренние чувства подсказывают мне, что он должен работать без дополнительной настройки, поскольку процесс разрешения ресурса для обработки запроса основан на точном совпадении с шаблонами URL. Я посмотрю и отвечу. Спасибо, что побудили меня расширить свои знания! :-)
Яцек Ласковски
Я использую, @ApplicationPath("")чтобы мои службы REST находились в корне (относительно корневого контекста webapp) на JBoss EAP 7. У меня нет ни, beans.xmlни web.xml.
Жюльен Кронегг 01
7

Вам необходимо настроить правильные зависимости в pom.xml

<dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
    </dependency>

Подробнее здесь: Пример стартера для jax-rs

ACV
источник
могу ли я удалить web.xml, если используется ResourceConfig / Application?
BAE
да, но вам нужно добавить это в pom.xml i fusnig mave:<failOnMissingWebXml>
ACV
Благодарю. но есть ли что-нибудь, что может сделать web.xml, но не может ResourceConfig?
BAE
Нет, я думаю, поскольку спецификация сервлета 3.0 web.xml больше не требуется. Но иногда удобнее использовать web.xml, поскольку он не требует перекомпиляции, если вы хотите что-то изменить.
ACV,
А что, если вы не используете Maven ? Мой проект сейчас слишком велик, чтобы переключиться обратно.
TheRealChx101
1

Ранее упомянутые зависимости у меня не работали. Из Руководства пользователя Джерси:

Jersey предоставляет два модуля сервлетов. Первый модуль - это базовый модуль сервлетов Jersey, который обеспечивает поддержку интеграции основных сервлетов и требуется в любом контейнере сервлета 2.5 или выше:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet-core</artifactId>
</dependency>

Для поддержки дополнительных режимов развертывания Servlet 3.x и асинхронной модели программирования ресурсов JAX-RS требуется дополнительный модуль Jersey:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet</artifactId>
</dependency>

Модуль jersey-container-servlet зависит от модуля jersey-container-servlet-core, поэтому при его использовании нет необходимости явно объявлять зависимость jersey-container-servlet-core.

https://jersey.github.io/documentation/latest/deployment.html#deployment.servlet.3

бзак
источник
0

Как отметил @ Eran-Medan, JBoss EAP 7.1 (примечание без веб-приложения, поэтому без сервлета, я делал это в проекте EJB 3.2) мне пришлось добавить атрибут «значение» как таковой, поскольку я получал исключение, что Атрибут value был обязательным.

Это сработало для меня

    @ApplicationPath(value="/*")
        public class MyApplication extends Application {

            private Set singletons = new HashSet();

            public MyApplication() {
                singletons.add(new MyService());
            }

            ...
    }

Трассировки стека

    Caused by: java.lang.annotation.IncompleteAnnotationException: javax.ws.rs.ApplicationPath missing element value
        at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:80)
        at com.sun.proxy.$Proxy141.value(Unknown Source)
        ... 21 more
JGlass
источник