以下のようなソースコード構造のJava EE Webアプリケーションを作っています。
src/main/java <-- multiple packages containing java classes
src/test/java <-- multiple packages containing JUnit tests
src/main/resources <-- includes properties files for textual messages
src/main/webapp/resources <-- includes CSS, images and all Javascript files
src/main/webapp/WEB-INF
src/main/webapp/WEB-INF/tags
src/main/webapp/WEB-INF/views
私が興味を持っているのはWEB-INF
という部分で、サーブレットやSpring Beanの配線コンテクスト、JSPのタグやビューを設定するためのXMLファイルであるweb.xml
が含まれています。
この構造の制約や定義を理解しようとしています。例えば、JSPファイルは常にWEB-INF
内になければならないのでしょうか、それとも他の場所にあってもいいのでしょうか?また、WEB-INF
の中に入るものは他にもあるのでしょうか?WikipediaのWARファイルのエントリーでは、Javaクラスのためのclasses
とJARファイルのためのlib
について言及されていますが、他のソースファイルの場所に加えて、これらがいつ必要になるのかを完全に理解しているわけではありません。
Servlet 2.4 specification]1には、WEB-INFについて次のように書かれています(70ページ)。
WEB-INF
という名前の特別なディレクトリがアプリケーション階層内に存在します。 という名前の特別なディレクトリが存在します。このディレクトリには、アプリケーションに関連するすべてのものが含まれています。 このディレクトリには、アプリケーションのドキュメントルートにない、アプリケーションに関連するすべてのものが含まれます。**以下は WEB-INFノードは、アプリケーションのパブリックドキュメントツリーの一部ではありません。 アプリケーションの公開ドキュメントツリーに含まれていません。WEB-INF
ディレクトリに含まれるファイルは、アプリケーションのドキュメントルートではない コンテナからクライアントに直接提供することはできません。ただし、WEB-INF
ディレクトリの内容は、クライアントに直接提供することはできません。 しかし、WEB-INF
ディレクトリの内容は、サーブレットコードがgetResource
とgetResource
を使って見ることができます。 サーブレットコードからは、ServletContext
のgetResource
およびgetResourceAsStream
メソッドコールを使って見ることができます。 また、RequestDispatcher
コールを使用して公開されることもあります。
つまり、WEB-INF
のリソースは、Webアプリケーションのリソースローダからアクセス可能であり、一般には直接公開されないということです。
多くのプロジェクトがJSPファイルやJAR/ライブラリ、独自のクラスファイルやプロパティファイル、その他の機密情報などのリソースをWEB-INF
フォルダに格納しているのはこのためです。そうしないと、単純な静的URLでアクセスできてしまいます(例えば、CSSやJavascriptを読み込むのに便利です)。
技術的な観点から言えば、JSPファイルはどこにでも置くことができます。例えばSpringでは、JSPファイルを明示的にWEB-INF
に置くように設定できます。
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" >
</bean>
Wikipedia'のWARファイルの記事で紹介されているWEB-INF/classes
とWEB-INF/lib
のフォルダは、Servletの仕様で実行時に必要なフォルダの例です。
プロジェクトの構造と結果としてのWARファイルの構造の違いを明確にすることが重要です。
プロジェクトの構造はWARファイルの構造を部分的に反映する場合があります(JSPファイルやHTML、JavaScriptファイルなどの静的リソースの場合ですが、必ずしもそうではありません)。
***プロジェクトの構造から結果のWARファイルへの移行は、ビルドプロセスによって行われます。
通常、ビルドプロセスは自由に設計することができますが、最近ではApache Mavenのような標準化されたアプローチを使用する人がほとんどです。とりわけMavenは、プロジェクト構造内のどのリソースが、結果として得られる成果物(この場合、結果として得られる成果物はWARファイル)内のどのリソースにマッピングされるかについて、デフォルトを定義しています。マッピングは単純なコピー処理からなる場合もあれば、フィルタリングやコンパイルなどの変換処理を含む場合もあります。
*一例を挙げます。WEB-INF/classesフォルダには、アプリケーションを起動するためにクラスローダによってロードされる必要のある、コンパイルされたすべてのJavaクラスとリソース(
src/main/javaと
src/main/resources`)が格納されます。
別の例です。WEB-INF/libフォルダーには、アプリケーションが必要とするすべての jar ファイルが格納されます。mavenプロジェクトでは依存関係が管理され、必要なjarファイルはmavenが自動的に
WEB-INF/libフォルダにコピーしてくれます。これが、mavenプロジェクトに
lib`フォルダがない理由です。
Java EEのWebアプリケーションを(フレームワークを使用しているかどうかに関わらず)デプロイする場合、その構造はいくつかの要件/仕様に従わなければなりません。これらの仕様は以下の通りです。
- サーブレットコンテナ(Tomcatなど)
- JavaサーブレットAPI
お客様のアプリケーションドメイン
1.Servletコンテナの要件
Apache Tomcatを使用している場合、アプリケーションのルートディレクトリはwebappフォルダ内に配置する必要があります。他のサーブレットコンテナやアプリケーションサーバーを使用している場合は、異なる場合があります。
2.Java Servlet APIの要件
Java Servlet APIでは、アプリケーションのルートディレクトリは以下のような構造になっている必要があります。
アプリケーション名
|
|--META-INF
|--WEB-INF
|_web.xml <--ここには、ウェブアプリの設定ファイル(サーブレット、フィルター、リスナーなどを定義します)があります。
|_classes <--あなたが定義したパッケージ構造に従って、Webアプリのすべてのクラスが表示されます。のみです。
|_lib <--ここには、アプリケーションに必要なすべてのライブラリ(jar)が入ります。
これらの要件は、Java Servlet APIで定義されています。
3.アプリケーションのドメイン
です。
Servletコンテナ(またはアプリケーションサーバー)の要件とJava Servlet APIの要件に従った後は、必要に応じてWebアプリの他の部分を整理します。
- リソース(JSPファイル、プレーンテキストファイル、スクリプトファイル)をアプリケーションのルートディレクトリに置くことができます。しかし、その場合、アプリケーションが提供するロジックによってリクエストが処理されるのではなく、ユーザーはブラウザから直接リソースにアクセスすることができてしまいます。そこで、リソースが直接アクセスされるのを防ぐために、サーバーからしかアクセスできないWEB-INFディレクトリにリソースを置くことができます。これらのフレームワーク(struts、spring、hibernate)の多くは、設定ファイルをクラスパス("classes"ディレクトリ)に置く必要があります。
公開したくないページやページの一部は、WEB-INFに置くべきです。通常、JSPやフェイスレットはWEB-INFの外に置かれますが、この場合はどのユーザーからも簡単にアクセスできます。また、認証に制限がある場合には、WEB-INFを利用することができます。
WEB-INF/libには、システムレベルではパッケージ化したくないサードパーティのライブラリ(JARはサーバー上で動作するすべてのアプリケーションで利用可能)を、この特定のアプリケーションのためだけに格納することができます。
一般的に、多くの設定ファイルもWEB-INFに入ります。
WEB-INF/classesについては、すべてのウェブアプリに存在します。なぜなら、それはすべてのコンパイルされたソース(JARSではなく、自分で書いたコンパイルされた.javaファイル)が置かれるフォルダだからです。