Shi*_*gon 24 java tomcat servlets java-ee
我有一个精简测试项目,其中包含一个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();
}
}
Run Code Online (Sandbox Code Playgroud)
我也有一个像这样的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>
Run Code Online (Sandbox Code Playgroud)
我尝试使用嵌入式Tomcat 7进行JUnit测试.当我启动嵌入式Tomcat时,我只能通过web.xml(/ testWebXml)中声明的url-pattern访问servlet.如果我尝试通过注释(/ test)声明的url-pattern访问它,则找不到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();
Run Code Online (Sandbox Code Playgroud)
为了确保我正确设置我的项目,我还安装了一个实际的Tomcat 7并部署了战争.这一次,web.xml声明的url和我的servlet的注释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>
Run Code Online (Sandbox Code Playgroud)
这是一个与此类似的问题(除了Servlet 3.0注释不起作用的是Listener,而不是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();
Run Code Online (Sandbox Code Playgroud)
我尝试过的其他事情也没有成功:
具体在web.xml"web-app"标签中设置metadata-complete ="false"
将Maven依赖项更新为7.0.30版
调试org.apache.catalina.startup.ContextConfig
类.那里有代码检查@WebServlet
注释,只是它永远不会被执行(第2115行).这可能是找到问题根源的好方法,但课程相当大,我现在没有时间这样做.也许如果有人愿意看看这个类是如何工作的,并且在哪些条件(config params)下它能够正确地检查项目的注释类,它可能会得到一个有效的答案.
Shi*_*gon 34
好吧,我终于通过查看Tomcat7源代码来解决它,即在处理EmbeddedTomcat和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();
Run Code Online (Sandbox Code Playgroud)
为了清楚起见,我应该提到这适用于标准的Maven项目,其中您的"Web资源"(例如静态和动态页面,WEB-INF目录等)可在以下位置找到:
[你项目的根目录]/src/main/webapp
并将您的课程编入
[你项目的根目录] /目标/类
(这样你就有[你的项目的根目录]/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();
Run Code Online (Sandbox Code Playgroud)