【问题标题】:How to set up JAX-RS Application using annotations only (no web.xml)?如何仅使用注释(无 web.xml)设置 JAX-RS 应用程序?
【发布时间】:2012-03-11 11:58:41
【问题描述】:

是否可以仅使用注释来设置 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>
   ...

Java

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

配置 B(不工作,抛出异常)

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

后者似乎坚持认为 Application 将是 Servlet 的子类(例外情况不容猜测)

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

问题

  1. 为什么 web.xml 定义有效但注释无效?有什么区别?

  2. 有没有办法让它工作,例如有没有 web.xml 的 JAX-RS 应用程序?

【问题讨论】:

  • 如果您可以尝试使用 NetBeans,这里有一个用于创建 RESTFul Web 服务的向导。看来您正在尝试做的是该向导在 6.8 版中所做的事情。我使用的是 7.0.1,新方法更简单,但使用单个 servlet,即 com.sun.jersey.spi.container.servlet.ServletContainer 但它在 web.xml 中定义

标签: java jakarta-ee jax-rs servlet-3.0


【解决方案1】:

** 如果您使用 TOMCAT 或 JETTY,请阅读! **

接受的答案确实有效,但前提是 web 应用程序部署到 Glassfish 或 Wildfly 等应用程序服务器,以及可能具有 EE 扩展的 servlet 容器,如 TomEE。它在标准 servlet 容器(如 Tomcat)上工作,我敢肯定大多数在这里寻找解决方案的人都想使用它。

如果您使用的是标准 Tomcat 安装(或其他一些 servlet 容器),则需要包含 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 {}

在此之后,可以直接在 Java 类中使用标准 JAX-RS 注释来声明 Web 服务:

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)。

【讨论】:

  • @JavaDude - 即使web.xml 不存在,您也必须配置 Maven 来构建 WAR 文件。在您的pom.xml 中,在“build > plugins”下,添加(如果还没有):&lt;plugin&gt;&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;&lt;version&gt;2.3&lt;/version&gt;&lt;configuration&gt;&lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;&lt;/configuration&gt;&lt;/plugin&gt;
  • @JavaDude - 重要的部分是&lt;failOnMissingWebXml&gt;false&lt;/fai‌​lOnMissingWebXml&gt; 选项。
  • @JavaDude - 如果不是这样,您可能没有创建扩展 Application 的类并向其添加 @ApplicationPath 注释。该类可以为空,但必须存在。
  • 只添加jersey-container-servlet就足够了,不需要拉整个jaxrs-ri依赖。例如。就我而言,它是'org.glassfish.jersey.core:jersey-server:2.18' + 'org.glassfish.jersey.containers:jersey-container-servlet:2.18'
  • 由于该问题已明确标记为“java-ee”,因此我不理解提供和支持不解决 jee 环境的答案的模糊性。 -1
【解决方案2】:

看来我需要做的就是这个(Servlet 3.0及以上)

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

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

显然不需要 web.xml 配置(在 Tomcat 7 上尝试过)

【讨论】:

  • 不明白这是怎么回事,你可以只使用注解而不进行任何其他配置吗?我已经尝试过这样但仍然无法正常工作......
  • @Filipe:我猜您正在使用 Tomcat 或其他一些 servlet 容器。这实际上不适用于 Tomcat 之类的 servlet 容器——它仅适用于 Glassfish 或 Wildfly 之类的应用服务器,也许还有 TomEE。如果您使用的是 Tomcat,请参阅下面我的(迟到的)答案。
  • 此答案不适用于 Tomcat 或 Jetty! 请参阅我的答案以使这些(和其他)servlet 容器中的东西正常工作。
  • 根据您的实现,您确实需要一个 web.xml,尽管一个空的就足够了。见docs.jboss.org/resteasy/docs/3.0.9.Final/userguide/html_single/…
  • 这适用于 WebSphere Liberty,但不适用于 WebSphere 8.x 和 9.0 Classic。
【解决方案3】:

JAX-RS: Java™ API for RESTful Web Services 规范的第 2 章描述了 JAX-RS 应用程序在 Servlet 环境中的发布过程(规范中的 2.3.2 Servlet 部分)。

请注意,仅推荐使用 Servlet 3 环境(第 2.3.2 节 Servlet,第 6 页):

建议实现支持 Servlet 3 框架可插拔机制,以实现之间的可移植性 容器并利用容器提供的类 扫描设施。

简而言之,如果您想使用 no-web.xml 方法,则可以使用 javax.ws.rs.core.Application 的自定义实现,使用 javax.ws.rs.ApplicationPath 注释注册 RESTful 服务资源。

@ApplicationPath("/rest")

尽管您特别询问了泽西岛,但您可能还想阅读文章 Implementing RESTful services with JAX-RS and WebSphere 8.5 Liberty Profile,其中我描述了 WebSphere Liberty Profile 的 no-web.xml 发布过程(使用 Apache Wink 作为 JAX-RS 的实现)。

【讨论】:

  • 谢谢!,我有另一个与此密切相关的问题让我发疯,有没有办法让路径在根目录中(例如 @ApplicationPath("/*") )并且仍然使用 JSP 服务只有注释? (尽管即使使用 web.xml 配置我也无法实现) - 问题在这里:stackoverflow.com/questions/10874188/…,因为您似乎非常了解 JAX-RS,请您看看吗? :) 也许你会看到我错过了什么......谢谢!
  • 我不知道。直觉告诉我,它应该在没有额外配置的情况下工作,因为解析资源以处理请求的过程是从精确匹配到 URL 模式。我会看看并回复。谢谢你鼓励我扩展我的知识! :-)
  • 我使用 @ApplicationPath("") 在 JBoss EAP 7 的根目录(相对于 webapp 上下文根目录)中拥有我的 REST 服务。我既没有 beans.xml 也没有 web.xml
【解决方案4】:

您需要在 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>

更多细节在这里: Starter example for jax-rs

【讨论】:

  • 如果使用了 ResourceConfig/Application,我可以删除 web.xml 吗?
  • 是的,但是你需要在 pom.xml 中添加这个我 fusnig mave:&lt;failOnMissingWebXml&gt;
  • 谢谢。但是有什么 web.xml 可以做而 ResourceConfig 不能吗?
  • 不,我认为因为 servlet spec 3.0 web.xml 不再需要。但有时使用 web.xml 更方便,因为如果您想更改某些内容,它不需要重新编译。
  • 如果您不使用 Maven 怎么办?我的项目现在太大了,无法切换回来。
【解决方案5】:

前面提到的依赖项对我不起作用。来自泽西用户指南:

Jersey 提供了两个 Servlet 模块。第一个模块是 Jersey 核心 Servlet 模块,它提供核心 Servlet 集成支持,并且在任何 Servlet 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

【讨论】:

    【解决方案6】:

    正如@Eran-Medan 指出的那样,JBoss EAP 7.1(注意没有 Web 应用程序所以没有 servlet,我在 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 2015-03-02
      • 2015-06-13
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      相关资源
      最近更新 更多