エラーが発生する理由は、属性404 File Not Found
の値として指定されたCSSへのパスにコンテキストパスがないためです。href
HTTPリクエストURLには、次の部分が含まれています。
http://[host]:[port][request-path]?[query-string]
リクエストパスは、さらに次の要素で構成されます。
コンテキストパス:スラッシュ(/)とサーブレットのWebアプリケーションのコンテキストルートを連結したもの。例:http://host[:port]/context-root[/url-pattern]
サーブレットパス:このリクエストをアクティブ化したコンポーネントエイリアスに対応するパスセクション。このパスはスラッシュ(/)で始まります。
パス情報:コンテキストパスまたはサーブレットパスの一部ではないリクエストパスの一部。
詳細はこちらをご覧ください。
ソリューション
あなたの問題にはいくつかの解決策があります、ここにそれらのいくつかがあります:
1)<c:url>
JSTLのタグを使用する
私のJavaWebアプリケーションでは、CSS / JavaScript / imageおよびその他の静的リソースへのパスを定義するときに、通常JSTL<c:url>
のタグを使用していました。そうすることで、これらのリソースが常にアプリケーションコンテキスト(コンテキストパス)に関連して参照されるようにすることができます。
CSSがWebContentフォルダー内にあると言う場合、これは機能するはずです。
<link type="text/css" rel="stylesheet" href="<c:url value="/globalCSS.css" />" />
それが機能する理由は、「JavaServerPages™標準タグライブラリ」バージョン1.2仕様の第7.5章(私の強調)で説明されています。
7.5 <c:url>
適切な書き換えルールが適用されたURLを作成します。
...
URLは、スキームで始まる絶対URL( "http:// server / context / page.jsp"など)またはJSP.2.2.1 "RelativeURLSpecificationのJSP1.2で定義されている相対URLのいずれかである必要があります。 "。結果として、実装は、スラッシュで始まるURL( "/page2.jsp"など)の前にコンテキストパスを追加して、そのようなURLがクライアントブラウザによって適切に解釈されるようにする必要があります。
注JSTLタグを参照できるようにするには、JSPでTaglibディレクティブ
を使用することを忘れないでください。こちらのJSPページの例も参照してください。
2)JSP式言語と暗黙オブジェクトの使用
別の解決策は、式言語(EL)を使用してアプリケーションコンテキストを追加することです。
<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/globalCSS.css" />
ここでは、リクエストオブジェクトからコンテキストパスを取得しました。また、リクエストオブジェクトにアクセスするために、pageContext 暗黙オブジェクトを使用しました。
3)<c:set>
JSTLのタグを使用する
免責事項
このソリューションのアイデアはここから取られました。
ソリューション№2よりもコンテキストパスへのアクセスをコンパクトにするために、最初にJSTL<c:set>
タグを使用できます。このタグは、任意のJSPスコープ(ページ、リクエスト、セッション)でEL変数の値またはEL変数のプロパティを設定します。 、またはアプリケーション)後でアクセスします。
<c:set var="root" value="${pageContext.request.contextPath}"/>
...
<link type="text/css" rel="stylesheet" href="${root}/globalCSS.css" />
重要な注意
デフォルトでは、このような方法で変数を設定するには、このsetタグを含むJSPに少なくとも1回アクセスする必要があります(たとえば、 scope属性を使用してアプリケーションスコープに値を設定する場合を含む)。新しい変数。たとえば、この変数が必要な場所に複数のJSPファイルを作成できます。したがって、a)アプリケーションスコープでコンテキストパスを保持する新しい変数を設定し、他のJSPファイルでこの変数を使用する前に最初にこのJSPにアクセスするか、b)必要に応じてすべてのJSPファイルでこのコンテキストパス保持変数を設定する必要があります。それにアクセスします。<c:set var="foo" value="bar" scope="application" />
4)ServletContextListenerの使用
コンテキストパスへのアクセスをよりコンパクトにするためのより効果的な方法は、コンテキストパスを保持する変数を設定し、リスナーを使用してそれをアプリケーションスコープに格納することです。このソリューションはソリューション№3に似ていますが、利点は、変数保持コンテキストパスがWebアプリケーションの開始時に設定され、アプリケーション全体で利用できるようになり、追加の手順が不要になることです。
ServletContextListenerインターフェースを実装するクラスが必要です。このようなクラスの例を次に示します。
package com.example.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
sc.setAttribute("ctx", sc.getContextPath());
}
@Override
public void contextDestroyed(ServletContextEvent event) {}
}
これで、JSPで、ELを使用してこのグローバル変数にアクセスできます。
<link type="text/css" rel="stylesheet" href="${ctx}/globalCSS.css" />
注
@WebListenerアノテーションは、サーブレットバージョン3.0以降で使用できます。古いサーブレット仕様をサポートするサーブレットコンテナまたはアプリケーションサーバーを使用する場合は、@ WebServletアノテーションを削除し、代わりにデプロイメント記述子(web.xml)でリスナーを構成します。これは、最大のサーブレットバージョン2.5をサポートするコンテナのweb.xmlファイルの例です(簡潔にするために、他の構成は省略されています)。
<?xml version="1.0" encoding="UTF-8"?>
<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_2_5.xsd"
version="2.5">
...
<listener>
<listener-class>com.example.listener.AppContextListener</listener-class>
</listener>
...
</webapp>
5)スクリプトレットの使用
ユーザー@gavenkoaが提案したように、次のようなスクリプトレットを使用することもできます。
<%= request.getContextPath() %>
このような小さなことについては、おそらく問題ありませんが、JSPでのスクリプトレットの使用は一般的に推奨されていないことに注意してください。
結論
私は個人的に、最初のソリューション(以前のプロジェクトでほとんどの場合に使用)または2番目のソリューションのいずれかを好みます。これは、それらが最も明確で、直感的で、明確であるためです(IMHO)。しかし、あなたは自分に最も合ったものを選びます。
他の考え
Webアプリをデフォルトのアプリケーションとして(つまり、デフォルトのルートコンテキストで)デプロイできるため、コンテキストパスを指定せずにアクセスできます。詳細については、こちらの「更新」セクションをお読みください。