使用web.xml、Servlet 3.0和Jersey部署JAX-RS应用程序



我正在尝试使用web.xml、servlet3.0和jersey API部署我的应用程序。不幸的是,它不起作用。

这是MyApplication.class:

package com.example;
public class MyApplication extends Application {
   public Set<Class<?>> getClasses() {
       Set<Class<?>> s = new HashSet<Class<?>>();
       s.add(MyResource.class);
       return s;
   }
}

这是MyResource:

@Path("/helloworld")
@Produces(MediaType.TEXT_PLAIN)
public class MyResource {
    @GET
    public String getHello() {
        return "HelloWorld !";
    }
}

还有我的web.xml:

 <web-app>
     <servlet>
         <servlet-name>com.example.MyApplication</servlet-name>
     </servlet>
     <servlet-mapping>
         <servlet-name>com.example.MyApplication</servlet-name>
         <url-pattern>/webapi/*</url-pattern>
     </servlet-mapping>
 </web-app>

在客户端,我使用以下网址:http://localhost:8080/[项目名称]/webapi/helloworld

我有一个错误:

java.lang.NullPointerException
    sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
    java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1629)
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:491)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1852)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    java.lang.Thread.run(Thread.java:662)

怎么了?:/我使用的是Tomcat 7。

PS:使用servlet 2.x,它可以工作:

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.example</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/webapi/*</url-pattern>
    </servlet-mapping>

但稍后我将需要异步模式。

谢谢!

更新:自从编写这个答案以来,我已经找到了一种方法,可以使用官方的Glassfish Jersey实现来避免在Tomcat上需要web.xml。查看此处了解详细信息。

如果您使用的是标准Tomcat安装(或其他servlet容器),AFAIK,那么您无法避免明确告诉它在web.xml文件*中启动哪些servlet。由于无论如何都必须使用web.xml,所以让restful web服务工作的最简单方法是完全忘记扩展javax.ws.rs.core.Application,只在那里指定上下文路径。您仍然可以使用标准的jax-rs注释来声明实际的web服务。

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
>
  <servlet>
    <servlet-name>rest-test</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.domain.mypackage</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name> rest-test</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

两个值得注意的点:

  1. 您将需要在WAR文件中捆绑REST实现,因为servlet容器通常不包含REST实现。由于Jersey是JAX-RS的参考实现,所以我在上面的servlet-class元素中使用了它。如果需要,可以用Apache CXF实现来代替它。

  2. init-param元素告诉Jersey要搜索哪个包中带有web服务注释的Java文件。编辑此以指向您的web服务。请注意,如果您选择使用apacheCXF而不是Jersey,那么任何init-param元素中所需的内容都将有所不同。了解CXF的人请发布他们会是什么。

如果您使用的是Maven,只需在pom.xml文件的dependencies部分向jersey-servlet添加一个依赖项:

<dependencies>
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-servlet</artifactId>
    <version>1.18.2</version>
  </dependency>
  ...
</dependencies>

在此之后,使用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)。

干杯!

*如果您知道在不使用web.xml的情况下将Jersey servlet添加到Tomcat中的上下文的方法,请有人纠正我的错误——可能是使用上下文或生命周期侦听器?

您需要在web-INF文件夹下创建web.xml,并使用以下代码行

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>ServletAdaptor</servlet-name>
        <servlet-class>
            org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>package where MyResource  resides</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletAdaptor</servlet-name>
        <url-pattern>/webresources/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

现在您可以删除您的MyApplication类。部署和测试web服务。它将工作

package com.example;
@ApplicationPath("/webapi")
public class MyApplication extends Application {
     public Set<Class<?>> getClasses() {
       Set<Class<?>> s = new HashSet<Class<?>>();
       s.add(MyResource.class);
       return s;
   }
}

访问此链接可能会有所帮助:https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.2

第4.7.1节。Servlet 2.x容器

<web-app>
    <servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            ...
        </init-param>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>MyApplication</servlet-name>
        <url-pattern>/myApp/*</url-pattern>
    </servlet-mapping>
    ...
</web-app>

最新更新