我有一个简化的测试项目,其中包含一个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- 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
我已经尝试过了,但没有成功:
将嵌入式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”标记中专门设置meta-complete =“ false”
将Maven依赖项更新到7.0.30版
调试org.apache.catalina.startup.ContextConfig类。那里有检查@WebServlet注解的代码,只是它从未执行过(第2115行)。这可能是解决问题根源的一种好方法,但是班级很多,我现在没有时间这样做。也许如果有人愿意看看这个类是如何工作的,以及它是在什么条件下(配置参数)正确地检查项目的类中的注释,它可能会得到一个有效的答案。
org.apache.catalina.startup.ContextConfig
@WebServlet
好吧,我终于通过查看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 / [某些软件包] /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();