150

2 つの異なるコンテナー (Tomcat と Jetty) に Web アプリケーションをデプロイしますが、静的コンテンツを提供するためのデフォルトのサーブレットは、使用したい URL 構造を処理する方法が異なります (詳細)。

したがって、独自の静的コンテンツ (画像、CSS など) を提供するために、webapp に小さなサーブレットを含めることを検討しています。サーブレットには次のプロパティが必要です。

  • 外部依存なし
  • シンプルで信頼性の高い
  • ヘッダーのサポートIf-Modified-Since(つまり、カスタムgetLastModifiedメソッド)
  • (オプション) gzip エンコーディング、etags などのサポート

そのようなサーブレットはどこかで入手できますか? 私が見つけることができる最も近いものは、サーブレットブックの例 4-10です。

更新:私が使用したい URL 構造は、疑問に思っている場合に備えて、次のとおりです。

    <servlet-mapping>
            <servlet-name>main</servlet-name>
            <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
            <servlet-name>default</servlet-name>
            <url-pattern>/static/*</url-pattern>
    </servlet-mapping>

そのため、パスに対するものでない限り、すべての要求をメイン サーブレットに渡す必要がありstaticます。問題は、Tomcat のデフォルト サーブレットが ServletPath を考慮しないことです (そのため、メイン フォルダー内の静的ファイルを検索します) が、Jetty は考慮します (そのため、staticフォルダー内を検索します)。

4

14 に答える 14

56

私は少し異なる解決策を思いつきました。少しハックっぽいですが、マッピングは次のとおりです。

<servlet-mapping>   
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
 <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>myAppServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

これは基本的に、拡張子ごとにすべてのコンテンツ ファイルをデフォルトのサーブレットにマップし、それ以外はすべて "myAppServlet" にマップするだけです。

Jetty と Tomcat の両方で動作します。

于 2010-08-27T07:36:52.483 に答える
46

この場合、デフォルトのサーブレットを完全にカスタム実装する必要はありません。この単純なサーブレットを使用して、リクエストをコンテナの実装にラップできます。


package com.example;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class DefaultWrapperServlet extends HttpServlet
{   
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        RequestDispatcher rd = getServletContext().getNamedDispatcher("default");

        HttpServletRequest wrapped = new HttpServletRequestWrapper(req) {
            public String getServletPath() { return ""; }
        };

        rd.forward(wrapped, resp);
    }
}
于 2009-05-07T21:00:08.520 に答える
30

FileServletはほぼすべての HTTP (etag、チャンクなど) をサポートしているため、良い結果が得られました。

于 2009-09-23T18:24:55.683 に答える
20

私は自分自身を転がしてしまいましたStaticServlet。gzipエンコーディングをサポートしておりIf-Modified-Since、warファイルから静的ファイルも提供できるはずです。それほど難しいコードではありませんが、完全に些細なことでもありません。

コードが利用可能です:StaticServlet.java。コメントしてください。

更新: KhurramはでServletUtils参照されているクラスについて質問しStaticServletます。これは、プロジェクトで使用した補助メソッドを持つクラスです。必要な唯一のメソッドはcoalesce(SQL関数と同じですCOALESCE)です。これはコードです:

public static <T> T coalesce(T...ts) {
    for(T t: ts)
        if(t != null)
            return t;
    return null;
}
于 2008-09-25T12:14:08.017 に答える
12

上記の例の情報から判断すると、この記事全体が Tomcat 6.0.29 以前のバグのある動作に基づいていると思います。https://issues.apache.org/bugzilla/show_bug.cgi?id=50026を参照してください。Tomcat 6.0.30 にアップグレードすると、(Tomcat|Jetty) 間の動作がマージされます。

于 2011-02-17T22:48:10.193 に答える
12

これを試して

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.css</url-pattern>
    <url-pattern>*.ico</url-pattern>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.htc</url-pattern>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>    

編集: これは、サーブレット 2.5 仕様以降でのみ有効です。

于 2012-01-28T14:45:43.043 に答える
11

同じ問題が発生し、Tomcatコードベースの「デフォルトサーブレット」のコードを使用して解決しました。

https://github.com/apache/tomcat/blob/master/java/org/apache/catalina/servlets/DefaultServlet.java

DefaultServletは、Tomcatの静的リソース(jpg、html、css、gifなど)を提供するサーブレットです。

このサーブレットは非常に効率的であり、上記で定義したいくつかのプロパティがあります。

このソースコードは、不要な機能や依存関係を開始して削除するための良い方法だと思います。

  • org.apache.naming.resourcesパッケージへの参照は、削除するか、java.io.Fileコードに置き換えることができます。
  • org.apache.catalina.utilパッケージへの参照は、ソースコードで複製できるユーティリティメソッド/クラスのみである可能性があります。
  • org.apache.catalina.Globalsクラスへの参照は、インライン化または削除できます。
于 2008-09-25T08:22:39.197 に答える
5

いくつかの回避策について、ウェブ上で素晴らしいチュートリアルを見つけました。シンプルで効率的です。REST urls スタイルのアプローチを使用したいくつかのプロジェクトで使用しました。

http://www.kuligowski.pl/java/rest-style-urls-and-url-mapping-for-static-content-apache-tomcat,5

于 2009-08-28T09:53:18.660 に答える
4

これは、Tomcat のDefaultServlet ( src ) を拡張し、getRelativePath() メソッドをオーバーライドすることで実現しました。

package com.example;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.servlets.DefaultServlet;

public class StaticServlet extends DefaultServlet
{
   protected String pathPrefix = "/static";

   public void init(ServletConfig config) throws ServletException
   {
      super.init(config);

      if (config.getInitParameter("pathPrefix") != null)
      {
         pathPrefix = config.getInitParameter("pathPrefix");
      }
   }

   protected String getRelativePath(HttpServletRequest req)
   {
      return pathPrefix + super.getRelativePath(req);
   }
}

...そして、これが私のサーブレットマッピングです

<servlet>
    <servlet-name>StaticServlet</servlet-name>
    <servlet-class>com.example.StaticServlet</servlet-class>
    <init-param>
        <param-name>pathPrefix</param-name>
        <param-value>/static</param-value>
    </init-param>       
</servlet>

<servlet-mapping>
    <servlet-name>StaticServlet</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>  
于 2009-09-23T18:19:10.053 に答える
1

Tomcat 8.x を確認済み: ルート サーブレットが "" にマップされている場合、静的リソースは正常に動作します。サーブレット 3.x の場合、次のようにして実行できます。@WebServlet("")

于 2017-01-08T10:04:21.280 に答える
1

Spring アプリからのすべてのリクエスト、および /favicon.ico と、Spring の AbstractUrlBasedView がリクエストする /WEB-INF/jsp/* からの JSP ファイルを処理するには、jsp サーブレットとデフォルト サーブレットを再マップするだけです。

  <servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>/WEB-INF/jsp/*</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/favicon.ico</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

jsp サーブレットの標準マッピングで *.jsp url-pattern に依存することはできません。拡張子のマッピングがチェックされる前にパス パターン '/*' が照合されるためです。jsp サーブレットをより深いフォルダーにマップするということは、それが最初に一致することを意味します。「/favicon.ico」のマッチングは、パス パターン マッチングの前に正確に行われます。より深いパスの一致、または完全一致は機能しますが、拡張子の一致は「/*」パスの一致を超えることはできません。デフォルトのサーブレットへの「/」のマッピングが機能していないようです。springapp では、正確な '/' の方が '/*' パス パターンよりも優れていると思われるでしょう。

上記のフィルター ソリューションは、アプリケーションから転送された、または含まれている JSP 要求に対しては機能しません。それを機能させるには、フィルターを springapp に直接適用する必要がありました。その時点で、アプリケーションに送られるすべてのリクエストもそのフィルターに送られるため、url-pattern マッチングは役に立ちませんでした。そこで、フィルタにパターン マッチングを追加し、「jsp」サーブレットについて学び、デフォルトのサーブレットのようにパス プレフィックスを削除しないことを確認しました。それは私の問題を解決しました。これはまったく同じではありませんが、十分に一般的でした。

于 2009-09-27T11:54:16.400 に答える
0

org.mortbay.jetty.handler.ContextHandler を使用します。StaticServlet のような追加のコンポーネントは必要ありません。

桟敷ホームでは、

$ cd コンテキスト

$ cp javadoc.xml static.xml

$ vi static.xml

...

<Configure class="org.mortbay.jetty.handler.ContextHandler">
<Set name="contextPath">/static</Set>
<Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/static/</Set>
<Set name="handler">
  <New class="org.mortbay.jetty.handler.ResourceHandler">
    <Set name="cacheControl">max-age=3600,public</Set>
  </New>
 </Set>
</Configure>

URL プレフィックスを使用して contextPath の値を設定し、resourceBase の値を静的コンテンツのファイル パスとして設定します。

それは私のために働いた。

于 2009-02-17T21:19:30.067 に答える
-1

JSOS の StaticFile を参照してください: http://www.servletsuite.com/servlets/staticfile.htm

于 2009-06-27T06:15:55.097 に答える