25

次のようなアノテーションで宣言されたサーブレットバージョン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> 

Embedded Tomcat 7を使用してJUnitテストを実行しようとしました。EmbeddedTomcatを起動すると、web.xml(/ testWebXml)で宣言されたurl-patternを介してのみサーブレットにアクセスできます。アノテーション(/ 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();

プロジェクトを正しく設定したことを確認するために、実際のTomcat 7もインストールして、戦争を展開しました。今回は、web.xmlで宣言されたURLとサーブレットのアノテーションURLの両方が正常に機能します。

だから私の質問は:Embedded Tomcat 7に私のサーブレット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>

==更新==

これに似ているように見える問題があります(動作していないサーブレット3.0アノテーションがサーブレットではなくリスナーにあることを除いて)、推奨される修正があります:

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

私はそれを試しましたが、うまくいきませんでした:

EmbeddedTomcatの開始コードを次のように変更しました。

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」タグにmetadata-complete="false"を設定します

  • Mavenの依存関係をバージョン7.0.30に更新する

  • org.apache.catalina.startup.ContextConfigクラスのデバッグ。そこに@WebServlet注釈をチェックするコードがあります、それはそれが決して実行されないということだけです(2115行目)。これは問題の根本を突き止めるための良い方法かもしれませんが、クラスはかなり大きく、今はこれを行う時間がありません。誰かがこのクラスがどのように機能するか、そしてどのような条件下(config params)でそのアノテーションについてプロジェクトのクラスを正しくチェックするかを喜んで見てくれるなら、それは有効な答えを得るかもしれません。

4

4 に答える 4

39

さて、Tomcat7ソース、つまりEmbeddedTomcatとサーブレット3.0アノテーションを処理する単体テストを調べることで最終的に解決しました。

基本的に、Ambedded 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();

わかりやすくするために、これは「Webリソース」(静的および動的ページ、WEB-INFディレクトリなど)が次の場所にある標準のMavenプロジェクトで機能することを説明しておきます。

[プロジェクトのルートディレクトリ]/src / main / webapp

そしてあなたのクラスはにコンパイルされます

[プロジェクトのルートディレクトリ]/target / classes

([プロジェクトのルートディレクトリ] /target/classes/[一部のパッケージ]/SomeCompiledServletClass.classがあるように)

他のディレクトリレイアウトの場合、これらの場所はそれに応じて変更する必要があります。

====更新:組み込みTomcat 8 ====

これに気づいてくれた@kwakに感謝します。

APIが少し変更されました。ここでは、EmbeddedTomcat8を使用した場合の上記の例の変更方法を説明します。

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();
于 2012-10-02T10:43:50.587 に答える
2
    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();

MVNのTomcatEmbed7.0.90を使用するとうまく機能します

于 2018-07-21T03:23:25.857 に答える
0

投稿したスニペットにJNDIの魔法があるとすると、次のようになります。

try {
    listBindings = context.getResources().listBindings(
            "/WEB-INF/classes");
} catch (NameNotFoundException ignore) {
    // Safe to ignore
}

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);
于 2012-10-01T16:48:08.773 に答える
-1

8.5以降では、それはたった1つのライナーだと思います。

Context.setAddWebinfClassesResources(true);

/ WEB-INF / classesを展開されたJARのように扱い、JARリソースをJAR内にあるかのように利用可能にするかどうかを示すフラグを設定します。

http://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/core/StandardContext.html#setAddWebinfClassesResources(boolean)

于 2020-04-07T05:35:29.833 に答える