java 嵌入式 tomcat 7 servlet 3.0 注释不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11669507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Embedded tomcat 7 servlet 3.0 annotations not working
提问by Shivan Dragon
I have a stripped down test project which contains a Servlet version 3.0, declared with annotations like so:
我有一个精简的测试项目,其中包含一个 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();
}
}
I also have a web.xml file like so:
我也有一个像这样的 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>
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.
我尝试使用嵌入式 Tomcat 7 进行 JUnit 测试。当我启动嵌入式 Tomcat 时,我只能通过 web.xml (/testWebXml) 中声明的 url-pattern 访问 servlet。如果我尝试通过通过注释 (/test) 声明的 url-pattern 访问它,它说找不到 404 页面。
Here's the code for my test:
这是我的测试代码:
String webappDirLocation = "src/main/webapp/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.addWebapp("/jerseyTest", new File(webappDirLocation).getAbsolutePath());
tomcat.start();
tomcat.getServer().await();
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.
为了确保我正确设置了我的项目,我还安装了一个实际的 Tomcat 7 并部署了War。这一次,web.xml 为我的 servlet 声明了 url 和注释 url 工作正常。
So my question is: does anyone know how to make Embedded Tomcat 7 take into account my Servlet 3.0 annotations?
所以我的问题是:有谁知道如何让嵌入式 Tomcat 7 考虑到我的 Servlet 3.0 注释?
I should also state that it's a Maven project, and the pom.xml contains the following dependencies:
我还应该声明它是一个 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>
== 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:
这是一个似乎与此类似的问题(除了 Servlet 3.0 注释不在 Listener 上,而不是在 Servlet 上),它有一个建议的修复:
https://issues.apache.org/bugzilla/show_bug.cgi?id=53903
https://issues.apache.org/bugzilla/show_bug.cgi?id=53903
I've tried it and it didn't work:
我试过了,没有用:
Changed the Embedded Tomcat start code to:
将嵌入式 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();
Other things I've tried, also without success:
我尝试过的其他事情也没有成功:
specifically setting metadata-complete="false" in web.xml "web-app" tag
updating the Maven dependencies to version 7.0.30
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.
在 web.xml "web-app" 标签中专门设置 metadata-complete="false"
将 Maven 依赖项更新到版本 7.0.30
调试
org.apache.catalina.startup.ContextConfig
类。那里有检查@WebServlet
注释的代码,只是它永远不会被执行(第 2115 行)。这可能是找到问题根源的好方法,但是班级很大,我现在没有时间这样做。也许如果有人愿意看看这个类是如何工作的,以及在什么条件下(配置参数)可以正确检查项目的类以获取该注释,它可能会得到一个有效的答案。
回答by Shivan Dragon
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.
好吧,我最终通过查看 Tomcat7 源代码解决了它,即在处理 EmbeddedTomcat 和 servlet 3.0 注释的单元测试中。
Basically, you must start your Embedded Tomcat 7 like this to make it aware of your annotated classes:
基本上,您必须像这样启动嵌入式 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();
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:
为了清楚起见,我应该提到这适用于标准 Maven 项目,其中您的“Web 资源”(例如静态和动态页面、WEB-INF 目录等)位于:
[your project's root dir]/src/main/webapp
[你项目的根目录]/src/main/webapp
and your classes get compiled into
你的类被编译成
[your project's root dir]/target/classes
[你项目的根目录]/target/classes
(such that you'd have [your project's root dir]/target/classes/[some package]/SomeCompiledServletClass.class)
(这样你就有了 [你项目的根目录]/target/classes/[some package]/SomeCompiledServletClass.class)
For other directories layouts, these locations need to be changed accordingly.
对于其他目录布局,需要相应地更改这些位置。
==== UPDATE: Embedded Tomcat 8 ====
==== 更新:嵌入式 Tomcat 8 ====
Thanks to @kwak for noticing this.
感谢@kwak 注意到这一点。
The APIs have changed a bit, here how the above example changes when using Embedded Tomcat 8:
API 发生了一些变化,这里是使用 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();
回答by Student414
Tomcat tomcat = new Tomcat();
tomcat.setPort(port);
Context ctx = tomcat.addWebapp("/", new File(docBase).getAbsolutePath());
StandardJarScanner scan = (StandardJarScanner) ctx.getJarScanner();
scan.setScanClassPath(true);
scan.setScanBootstrapClassPath(true); // just guessing here
scan.setScanAllDirectories(true);
scan.setScanAllFiles(true);
tomcat.start();
tomcat.getServer().await();
it works well for me using Tomcat Embed 7.0.90 from MVN
使用 MVN 的 Tomcat Embed 7.0.90 对我来说效果很好
回答by tommyhp2
I think in 8.5 and later it's just one liner:
我认为在 8.5 及更高版本中它只是一个班轮:
Context.setAddWebinfClassesResources(true);
Context.setAddWebinfClassesResources(true);
Sets the flag that indicates if /WEB-INF/classes should be treated like an exploded JAR and JAR resources made available as if they were in a JAR.
设置指示是否应将 /WEB-INF/classes 视为分解的 JAR 并将 JAR 资源视为在 JAR 中可用的标志。
回答by Ian Roberts
Given the JNDI magic in the snippet you posted:
鉴于您发布的代码段中的 JNDI 魔法:
try {
listBindings = context.getResources().listBindings(
"/WEB-INF/classes");
} catch (NameNotFoundException ignore) {
// Safe to ignore
}
could you maybe set up the same sort of entries in JNDI yourself?
您可以自己在 JNDI 中设置相同类型的条目吗?
Context ctx = tomcat.addWebapp(...);
FileDirContext fdc = new FileDirContext();
fdc.setDocBase(new File("/path/to/my/classes").getAbsolutePath());
ctx.getResources().createSubcontext("/WEB-INF/classes").bind("myclasses", fdc);