25

我有一个精简的测试项目,其中包含一个 Servlet 3.0 版,使用如下注释声明:

    @WebServlet("/test")
public class TestServlet extends HttpServlet {

    private static final long serialVersionUID = -3010230838088656008L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
        response.getWriter().write("Test");
        response.getWriter().flush();
        response.getWriter().close();
    }
}

我也有一个 web.xml 文件,如下所示:

<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>testServlet</servlet-name>
        <servlet-class>g1.TestServlet</servlet-class>
      </servlet>      

      <servlet-mapping>
        <servlet-name>testServlet</servlet-name>
        <url-pattern>/testWebXml</url-pattern>
      </servlet-mapping>

</web-app> 

我尝试使用 Embedded Tomcat 7 进行 JUnit 测试。当我启动 Embedded Tomcat 时,我只能通过 web.xml (/testWebXml) 中声明的 url-pattern 访问 servlet。如果我尝试通过注释 (/test) 声明的 url 模式访问它,则找不到 404 页面。

这是我的测试代码:

    String webappDirLocation = "src/main/webapp/";
    Tomcat tomcat = new Tomcat();
    tomcat.setPort(8080);

    tomcat.addWebapp("/jerseyTest", new File(webappDirLocation).getAbsolutePath());

    tomcat.start();
    tomcat.getServer().await();

为了确保我正确设置了我的项目,我还安装了一个实际的 Tomcat 7 并部署了战争。这一次,我的 servlet 的 web.xml 声明的 url 和注释 url 都可以正常工作。

所以我的问题是:有谁知道如何让 Embedded Tomcat 7 考虑到我的 Servlet 3.0 注释?

我还应该声明它是一个 Maven 项目,并且 pom.xml 包含以下依赖项:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>7.0.29</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>7.0.29</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-jasper</artifactId>
        <version>7.0.29</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.1</version>
        <scope>test</scope>
    </dependency>

== 更新 ==

这是一个看起来与此类似的问题(除了不工作的 Servlet 3.0 注释在侦听器上,而不是在 Servlet 上),它有一个建议的修复:

https://issues.apache.org/bugzilla/show_bug.cgi?id=53903

我已经尝试过了,但没有奏效:

将 Embedded Tomcat 启动代码更改为:

String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();

tomcat.enableNaming();
tomcat.setPort(8080);


Context ctx = tomcat.addWebapp(tomcat.getHost(), "/embeddedTomcat", new File(webappDirLocation).getAbsolutePath());
((StandardJarScanner) ctx.getJarScanner()).setScanAllDirectories(true);

tomcat.start();

tomcat.getServer().await();

我尝试过的其他事情也没有成功:

  • 在 web.xml “web-app” 标签中专门设置 metadata-complete="false"

  • 将 Maven 依赖项更新到版本 7.0.30

  • 调试org.apache.catalina.startup.ContextConfig类。那里有检查@WebServlet注释的代码,只是它永远不会被执行(第 2115 行)。这可能是找到问题根源的好方法,但是课程很大,我现在没有时间这样做。也许如果有人愿意看看这个类是如何工作的,以及在什么条件下(配置参数)它可以正确地检查你的项目的类中的注释,它可能会得到一个有效的答案。

4

4 回答 4

39

好吧,我终于通过查看 Tomcat7 源代码解决了这个问题,即在处理 EmbeddedTomcat 和 servlet 3.0 注释的单元测试中。

基本上,您必须像这样启动您的 Embedded Tomcat 7 以使其知道您的注释类:

String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);

StandardContext ctx = (StandardContext) tomcat.addWebapp("/embeddedTomcat",
                new File(webappDirLocation).getAbsolutePath());

//declare an alternate location for your "WEB-INF/classes" dir:     
File additionWebInfClasses = new File("target/classes");
VirtualDirContext resources = new VirtualDirContext();
resources.setExtraResourcePaths("/WEB-INF/classes=" + additionWebInfClasses);
ctx.setResources(resources);

tomcat.start();
tomcat.getServer().await();

为了清楚起见,我应该提到这适用于标准 Maven 项目,您的“Web 资源”(例如静态和动态页面、WEB-INF 目录等)位于:

[你项目的根目录]/src/main/webapp

你的类被编译成

[你项目的根目录]/target/classes

(这样你就有了[你的项目的根目录]/target/classes/[some package]/SomeCompiledServletClass.class)

对于其他目录布局,需要相应地更改这些位置。

==== 更新:嵌入式 Tomcat 8 ====

感谢@kwak 注意到这一点。

API 发生了一些变化,以下是使用 Embedded Tomcat 8 时上述示例的变化:

String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);

StandardContext ctx = (StandardContext) tomcat.addWebapp("/embeddedTomcat",
                new File(webappDirLocation).getAbsolutePath());

//declare an alternate location for your "WEB-INF/classes" dir:     
File additionWebInfClasses = new File("target/classes");
WebResourceRoot resources = new StandardRoot(ctx);
resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
ctx.setResources(resources);

tomcat.start();
tomcat.getServer().await();
于 2012-10-02T10:43:50.587 回答
2
    Tomcat tomcat = new Tomcat();
    tomcat.setPort(port);

    Context ctx = tomcat.addWebapp("/", new File(docBase).getAbsolutePath());
    StandardJarScanner scan = (StandardJarScanner) ctx.getJarScanner();
    scan.setScanClassPath(true);
    scan.setScanBootstrapClassPath(true); // just guessing here
    scan.setScanAllDirectories(true);
    scan.setScanAllFiles(true);

    tomcat.start();
    tomcat.getServer().await();

使用 MVN 的 Tomcat Embed 7.0.90 对我来说效果很好

于 2018-07-21T03:23:25.857 回答
0

鉴于您发布的片段中的 JNDI 魔法:

try {
    listBindings = context.getResources().listBindings(
            "/WEB-INF/classes");
} catch (NameNotFoundException ignore) {
    // Safe to ignore
}

您可以自己在 JNDI 中设置相同类型的条目吗?

Context ctx = tomcat.addWebapp(...);
FileDirContext fdc = new FileDirContext();
fdc.setDocBase(new File("/path/to/my/classes").getAbsolutePath());
ctx.getResources().createSubcontext("/WEB-INF/classes").bind("myclasses", fdc);
于 2012-10-01T16:48:08.773 回答
-1

我认为在 8.5 及更高版本中它只是一个班轮:

Context.setAddWebinfClassesResources(true);

设置标志,指​​示是否应将 /WEB-INF/classes 视为爆炸的 JAR 和 JAR 资源,就像它们在 JAR 中一样。

http://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/core/StandardContext.html#setAddWebinfClassesResources(boolean)

于 2020-04-07T05:35:29.833 回答