全然知らなかったので、メモ的に。
Servlet 3.0から、JSPや静的ファイルをJARファイルの中に含めることができるようになっていたみたいです。
Tomcat 7も対応したServlet 3.0の6つの主な変更点 (3/3):Tomcat 7の新機能で何ができるようになるのか?(1) - @IT
JSP Container Pluggability-プラグ可能性 ← ただいまパキり中
10.5 ディレクトリ構造(Directory Structure)
ウェブ・アプリケーションはディレクトリたちの構造化された階層として存在する。この階層のルートがそのアプリケーションの要素であるファイルたちのドキュメント・ルートになる。例えば、あるウェブ・コンテナのなかで/catalog というコンテキスト・パスを持ったあるウェブ・アプリケーションでは、このアプリケーション階層のベースにある index.html ファイル、あるいは META-INF/resources ディレクトリ
https://www.cresc.co.jp/tech/java/Servlet_Specifications/Servlet_Specification_3_0_Japanese.pdf
のなかで index.html を含む WEB-INF/lib のなかの JAR ファイルのなかにある index.html ファイルは、/catalog/index.html からの要求を満足させるために使われる。もし index.html がルート・コンテキストの中、及びこのアプリケーションの WEB-INF/lib ディレクトリのなかの JAR ファイルの METAINF/resourcesディレクトリの中の双方に存在する場合は、そのルート・コンテキストの中で得られるファイルが使われねばならない。
なるほど?どうやら、JARファイル内の「META-INF/resources」配下にファイルを置き、WARファイル側の「WEB-INF/lib」ディレクトリに
配置すると、コンテナが中身のファイルを認識してくれる、と。パスがかぶった場合は、WARファイル側の方が優先される、という
ことみたいですね。
JSRも。
The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 340
The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 315
使うかな?どうかな?という気はしますが、とりあえず動かしてみるとしましょう。
サンプルコード
確認のために、簡単なMavenのマルチプロジェクトを作成します。ひとつは、JSPやテキストファイルのみを含めたJARファイル、
もうひとつはWebアプリケーション。WEB-INF配下にファイルを置くことも含めて、確認してみましょう。
Webアプリケーション側には、一部JARファイル内のパスと重複させたものも配置してみます。
親プロジェクト。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>jsp-in-jar</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <modules> <module>jsp-files</module> <module>web-app</module> </modules> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> </project>
JARファイル側のプロジェクト。
jsp-files/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jsp-in-jar</artifactId> <groupId>org.littlewings</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jsp-files</artifactId> </project>
配置しているファイルは、こんな感じです。
jsp-files/src/main/resources/META-INF/resources/hello.jsp jsp-files/src/main/resources/META-INF/resources/hello-duplicate.jsp jsp-files/src/main/resources/META-INF/resources/hello.txt jsp-files/src/main/resources/META-INF/resources/hello-duplicate.txt jsp-files/src/main/resources/META-INF/resources/WEB-INF/view/hello-webinf.jsp jsp-files/src/main/resources/META-INF/resources/WEB-INF/view/hello-webinf-duplicate.jsp
WEB-INF配下のファイルは、Webアプリケーション側に作成するServletからフォワードして使う感じで用意。
中身は、動作確認の時に記載します。
Webアプリケーション側。
web-app/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jsp-in-jar</artifactId> <groupId>org.littlewings</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>web-app</artifactId> <packaging>war</packaging> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.littlewings</groupId> <artifactId>jsp-files</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <build> <finalName>ROOT</finalName> </build> </project>
依存関係は、Sevlet API 3.1と先ほど作成しているJSPなどを含めたJARファイルです。
こちらのモジュールで作成したファイルは、こんな感じ。
web-app/src/main/webapp/hello-duplicate.txt web-app/src/main/webapp/hello-duplicate.jsp web-app/src/main/webapp/WEB-INF/view/hello-webinf-duplicate.jsp web-app/src/main/java/org/littlewings/servlet/HelloWebinfJspServlet.java web-app/src/main/java/org/littlewings/servlet/HelloWebinfDuplicateJspServlet.java
JARファイル側とパスを重複させたテキストファイルに、JSP、あとServletを2つ。
Servletは、Requestスコープに値を入れてWEB-INF配下にフォワードするだけのものです。
こちらは、JARファイル内にあるJSPにフォワードさせます。
web-app/src/main/java/org/littlewings/servlet/HelloWebinfJspServlet.java
package org.littlewings.servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/webinf/jsp") public class HelloWebinfJspServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setAttribute("word", "***Hello***"); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/hello-webinf.jsp"); rd.forward(request, response); } }
こちらは、WARファイル側とJARファイル側の両方にあるJSPにフォワードさせます。
web-app/src/main/java/org/littlewings/servlet/HelloWebinfDuplicateJspServlet.java
package org.littlewings.servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/webinf/duplicate-jsp") public class HelloWebinfDuplicateJspServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setAttribute("word", "***Hello***"); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/hello-webinf-duplicate.jsp"); rd.forward(request, response); } }
動作確認
それでは、パッケージングして動作確認してみましょう。
$ mvn package
Webアプリケーション側のモジュールに、「ROOT.war」というファイルができあがります。WARファイルの中には、「WEB-INF/lib」
ディレクトリ内にJSPやテキストファイルを入れたJARファイルが置かれています。
$ jar -tvf web-app/target/ROOT.war 2941 Sat Jan 20 17:52:12 JST 2018 WEB-INF/lib/jsp-files-0.0.1-SNAPSHOT.jar
これを、今回はTomcatとWildFlyで確認してみます。
まずはTomcat 8.5.24を使って確認していきましょう。
JARファイル内にのみ存在するテキストファイル。
対象のファイル。
jsp-files/src/main/resources/META-INF/resources/hello.txt
Hello World!!
確認。
$ curl http://localhost:8080/hello.txt
Hello World!!
表示できました。
JARファイルとWARファイルの両方に存在するテキストファイル。
JARファイル側。
jsp-files/src/main/resources/META-INF/resources/hello-duplicate.txt
Hello World!!!!
WARファイル側。
web-app/src/main/webapp/hello-duplicate.txt
Hello World!!!!!!!!
確認。
$ curl http://localhost:8080/hello-duplicate.txt
Hello World!!!!!!!!
WARファイル側の方が優先されていますね。
ルート配下にあり、かつJARファイル内にのみあるJSPファイル
対象のファイル。
jsp-files/src/main/resources/META-INF/resources/hello.jsp
Hello JSP in JAR
確認。
$ curl http://localhost:8080/hello.jsp Hello JSP in JAR
JSPを認識して動きました。
ルート配下にあり、かつJARファイルにもWARファイルにも両方存在するJSPファイル
JARファイル側。
jsp-files/src/main/resources/META-INF/resources/hello-duplicate.jsp
Hello JSP!! in JAR
WARファイル側。
web-app/src/main/webapp/hello-duplicate.jsp
Hello JSP!!!! in WAR
確認。
$ curl http://localhost:8080/hello-duplicate.jsp Hello JSP!!!! in WAR
WARファイル側が表示されています。
WEB-INF配下にあり、JARファイル側に存在するJSPファイル
jsp-files/src/main/resources/META-INF/resources/WEB-INF/view/hello-webinf.jsp
${word} JSP in JAR(WEB-INF/view)
EL式を使いつつ、Servletからフォワードして使います。
確認。
$ curl http://localhost:8080/webinf/jsp ***Hello*** JSP in JAR(WEB-INF/view)
ちゃんと動きました。
WEB-INF配下にあり、JARファイルとWARファイルの両方に存在するJSPファイル
JARファイル側。
jsp-files/src/main/resources/META-INF/resources/WEB-INF/view/hello-webinf-duplicate.jsp
${word} JSP!! in JAR(WEB-INF/view)
WARファイル側。
web-app/src/main/webapp/WEB-INF/view/hello-webinf-duplicate.jsp
${word} JSP!!!! in WAR(WEB-INF/view)
確認。
$ curl http://localhost:8080/webinf/duplicate-jsp ***Hello*** JSP!!!! in WAR(WEB-INF/view)
WARファイル側が表示されました、と。
最後に、WildFly 11.0.0.Finalで確認してみます。こちらは、結果だけ。
$ curl http://localhost:8080/hello.txt Hello World!! $ curl http://localhost:8080/hello-duplicate.txt Hello World!!!!!!!! $ curl http://localhost:8080/hello.jsp Hello JSP in JAR $ curl http://localhost:8080/hello-duplicate.jsp Hello JSP!!!! in WAR $ curl http://localhost:8080/webinf/jsp ***Hello*** JSP in JAR(WEB-INF/view) $ curl http://localhost:8080/webinf/duplicate-jsp ***Hello*** JSP!!!! in WAR(WEB-INF/view)
Tomcatと、同じ結果になりましたね。
ちょっと覚えておきましょう。