嵌入式 tomcat 7 servlet 3.0 注释不起作用

2024-05-10

我有一个精简的测试项目,其中包含 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> 

我尝试使用嵌入式 Tomcat 7 进行 JUnit 测试。当我启动嵌入式 Tomcat 时,我只能通过 web.xml (/testWebXml) 中声明的 url 模式访问 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 并部署了 war。这次,web.xml 为我的 servlet 声明的 url 和注释 url 都工作正常。

所以我的问题是:有谁知道如何使嵌入式 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>

==更新==

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

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

我已经尝试过了,但没有成功:

将嵌入式 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 行)。这可能是解决问题根源的好方法,但是课程很大,我现在没有时间这样做。也许如果有人愿意看看这个类是如何工作的,以及在什么条件(配置参数)下它可以正确检查项目的类的该注释,它可能会得到一个有效的答案。


好吧,我最终通过查看 Tomcat7 源代码(即处理嵌入式 Tomcat 和 servlet 3.0 注释的单元测试)解决了这个问题。

基本上,您必须像这样启动嵌入式 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 发生了一些变化,以下是使用嵌入式 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();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式 tomcat 7 servlet 3.0 注释不起作用 的相关文章

随机推荐