嵌入式 tomcat 7 servlet 3.0 注释不起作用 [英] Embedded tomcat 7 servlet 3.0 annotations not working

查看:26
本文介绍了嵌入式 tomcat 7 servlet 3.0 注释不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a stripped down test project which contains a Servlet version 3.0, declared with annotations like so:

    @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 文件:

I also have a web.xml file like so:

<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-pattern 访问 servlet.如果我尝试通过通过注释 (/test) 声明的 url-pattern 访问它,它说找不到 404 页面.

I've tried to make a JUnit test using Embedded Tomcat 7. When I start the Embedded Tomcat I can only access the servlet via the url-pattern declared in web.xml (/testWebXml). If I try to access it via the url-pattern declared via annotation (/test) it sais 404 page not found.

这是我的测试代码:

    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 并部署了战争.这一次,web.xml 为我的 servlet 声明了 url 和 annotation url.

Just to make sure I've set up my project correctly, I've also installed an actual Tomcat 7 and deployed the war. This time, both web.xml declared url and annotation url for my servlet work ok.

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

So my question is: does anyone know how to make Embedded Tomcat 7 take into account my Servlet 3.0 annotations?

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

I should also state that it's a Maven project, and the pom.xml contains the following dependencies:

    <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 注释在 Listener 上不起作用,而不是在 Servlet 上),它有一个建议的修复:

== UPDATE ==

Here's an issue that seems similar to this (except the Servlet 3.0 annotation that is not working is on Listener, not Servlet), which has a suggested fix:

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

我试过了,没有用:

将嵌入式 Tomcat 启动代码更改为:

Changed the Embedded Tomcat start code to:

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();

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

Other things I've tried, also without success:

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

  • specifically setting metadata-complete="false" in web.xml "web-app" tag

将 Maven 依赖项更新到 7.0.30 版

updating the Maven dependencies to version 7.0.30

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

debugging the org.apache.catalina.startup.ContextConfig class. There's code there that checks for @WebServlet annotations, it's just that it never gets executed (line 2115). This may be a good way to get to the root of the issue, but the class is pretty big, and I don't have time to do this now. Maybe if someone would be willing to look how this class works, and under which conditions (config params) does it get to correctly check your project's classes for that annotation, it might get to a valid answer.

推荐答案

好吧,我终于通过查看 Tomcat7 源代码解决了它,即处理 EmbeddedTomcat 和 servlet 3.0 注释的单元测试.

Well I finally solved it by looking in the Tomcat7 sources, namely in the unit tests that deal with EmbeddedTomcat and servlet 3.0 annotations.

基本上,您必须像这样启动嵌入式 Tomcat 7 以使其了解您的注释类:

Basically, you must start your Embedded Tomcat 7 like this to make it aware of your annotated classes:

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-INF 目录等)位于:

For the sake of clarity I should mention that this works for a standard Maven project where your "web resources" (such as static and dynamic pages, WEB-INF directory etc) are found in:

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

[your project's root dir]/src/main/webapp

并且你的类被编译成

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

[your project's root dir]/target/classes

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

(such that you'd have [your project's root dir]/target/classes/[some package]/SomeCompiledServletClass.class)

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

For other directories layouts, these locations need to be changed accordingly.

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

==== UPDATE: Embedded Tomcat 8 ====

感谢@kwak 注意到这一点.

Thanks to @kwak for noticing this.

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

The APIs have changed a bit, here how the above example changes when using 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();

这篇关于嵌入式 tomcat 7 servlet 3.0 注释不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆