@WebServlet注解与Tomcat 7

63

在我的应用程序中,我有一个servlet,在web.xml文件中定义如下:

<servlet>
    <display-name>Notification Servlet</display-name>
    <servlet-name>NotificationServlet</servlet-name>
    <servlet-class>com.XXX.servlet.NotificationServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>NotificationServlet</servlet-name>
    <url-pattern>/notification/*</url-pattern>
</servlet-mapping>

在迁移到使用Tomcat 7之后,我想要使用@WebServlet注释来完成工作。
以下是我的做法:

@WebServlet( name="NotificationServlet", displayName="Notification Servlet", urlPatterns = {"/notification"}, loadOnStartup=1)
public class NotificationServlet extends HttpServlet {

它不起作用。 请问有人能告诉我做错了什么吗?


11
因为这个问题,我能够摆脱大量的样板式XML。感谢注解! - aroth
3个回答

114

如果你确信在使用Tomcat 7或更新版本,那么web应用程序的web.xml必须声明为符合Servlet 3.0规范,以便让Tomcat扫描和处理注释。否则,Tomcat仍会以与web.xml中相匹配的Servlet版本运行在后备模式下。对于servlet API注释的支持只在Servlet 3.0(Tomcat 7)中添加。

因此,你的web.xml的根声明必须如下所示(请确保从web.xml中删除任何DOCTYPE,否则它仍将被解释为Servlet 2.3!)。

<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">

此外,URL模式有微小的差别。URL模式/notifications将仅允许Servlet在该路径上监听请求。它不会在带有额外路径(如/notifications/list)的请求上启动。URL模式/notifications/*将使Servlet也能够监听带有额外路径信息的请求。

因此,最小的@WebServlet注释应如下所示:

@WebServlet("/notifications/*")

其余的属性是可选的,因此不是使servlet功能运行所必需的。

另请参阅:


1
你可能需要添加 <web-app (...) metadata-complete="false"></webapp> - Nicolas Zozol
3
在使用@WebServlet注解时,完全不需要使用web.xml文件。没有web.xml也可以正常工作。 - destan
1
@destan:没错。但是,如果你有一个版本,就像OP的情况一样,它必须至少是3.0。最终你需要一个版本,因为不是所有的东西都可以被注释。 - BalusC
@BalusC 但在servlet维基http://en.wikipedia.org/wiki/Java_Servlet中显示支持从版本2.5开始。虽然我测试了它,但它与版本2.5无法正常工作,需要版本3.0。但是在阅读servlet维基页面后,我有点困惑。 - Aniket
4
您的问题是:@Aniket: 您认为维基百科上的信息比甲骨文自己的Servlet规范文档中的信息更可靠?为什么呢? - BalusC
1
我有一个奇怪的情况,当我改变、编译并重新部署到glassfish 4时,servlet工作正常。但是,当我再次编译而没有任何更改,并且重新部署,它就不起作用了。我添加了metadata-complete="false"属性并最小化了webservlet注释,现在它可以工作了。尽管其他servlet一直工作正常。 - Herbert

6

您可能还需要检查是否存在具有相同名称注释的两个类:

@WebServlet(name = "Foo", urlPatterns = {"/foo"})
public class Foo extends HttpServlet {
    //...
}

并且:

@WebServlet(name = "Foo", urlPatterns = {"/bar"})
public class Bar extends HttpServlet {
    //...
}

在这种情况下,其中一个servlet将无法工作。如果您不使用名称,请像@BalusC建议的那样将其留空。 我曾经遇到过奇怪的行为,其中一个servlet仅在更改和编译后才能正确工作,但是在没有更改的情况下编译后无法工作。

1
如果您给出负面评价,请留下评论,否则没有人能够回应、纠正或从中学习。谢谢。 - Herbert

3
此外,为了使用这些注解并编译您的代码,您必须在pom.xml中导入相应的依赖项,但是只要您的“Servlet 3.0”兼容服务器已经具备此功能,就可以将其提供。
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接