【Java】warファイル作成~Webアプリケーション起動までの簡単な流れまとめ


warファイルをつくるための簡単なメモ。


 


 
非常に簡単なwarファイル「wartest.war」というWebアプリケーションをつくる。
フォルダ構成として以下のようなかんじ。

[ルート]  
│  warmake.bat             ....(A)  
│  wartest.war             ....(B)  
│  
├─html                    ....(1)  
│      Test.html  
│  
├─source                  ....(2)  
│      TestServlet.java  
│  
├─warmake                 ....(3)  
│  ├─html  
│  │      Test.html  
│  │  
│  └─WEB-INF  
│      │  web.xml  
│      │  
│      ├─classes  
│      │      TestServlet.class  
│      │  
│      └─lib  
│              j2ee.jar  
│  
└─WEB-INF                 ....(4)  
    │  web.xml  
    │  
    ├─classes  
    │      TestServlet.class  
    │  
    └─lib  
            j2ee.jar  

ただこれは俺がいつもこんな感じで作っているからというだけで、
絶対に必要かと問われるとそうでもないものも多い。
というかこの中でWebアプリとして動かすうえで絶対必須なのは(4)「WEB-INF」配下だけである。
一応この手順では(4)「WEB-INF」に加えて(1)「html」配下もwarファイルとして固めるが、
上述の通り(1)「html」はWebアプリケーションとして絶対必要な資産ではない。
その他についても個人的な好みが反映されてる部分が強いが、
とりあえずこのやり方でwarファイルを作るまでを簡単に紹介する。




(1)htmlフォルダ
文字通りhtmlを格納するフォルダ。
配下に1つだけ、「Test.html」という静的HTMLを用意しておく。
これは本当にただのマジモンの静的HTMLで、これ自体に動的要素は一切ない。
役割は「サーバへデータをリクエストする」ための入り口である。
こういうのがないと、サーブレットを用意したところで、
それを呼び出すにあたってブラウザでURLを直接叩かないと呼び出せないので、
こういうのが一つあったほうが便利なのである。
そういう意味では「サーブレット実行のためのショートカット」というのが一番分かりやすい表現か。

そしてそんな話なのであれば、
ローカルのどっか適当な場所にこのHTMLファイルが存在していればよく、
warファイルに含めてWebアプリケーション化する必要はない。
そういった点を踏まえても、上述した通り、別にこれはなくても全然支障はない。
なので、これをwarにいれてるというのは個人的な好みの色が強いのだろう。
まあ、参考になれば。
ちなみに↓のようなHTMLである。

  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>  
<head>  
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
	<meta HTTP-EQUIV='Cache-Control' CONTENT='no-cache'>  
	<meta HTTP-EQUIV='Pragma' CONTENT='no-cache'>  
	<meta HTTP-EQUIV='Expires' CONTENT='-1'>  
&lt;title&gt;test&lt;/title&gt;  

</head>
<body>
<form action="/wartest/TestServlet" method=“post”>
テストフォームです。<br/>
以下にパラメータを入力して[送信]ボタンを押下すると、<br/>
サーバにデータを送信します。<br/>
<input type=“text” value="" id=“param” name=“param” maxlength=“2”/><br/>
<br/>
<input type=“submit” value=“送信”/>
</form>
</body>
</html>





(2)sourceフォルダ
サーブレットのソースファイルを格納するフォルダ。
リクエスト受け付けて、パラメータの値を出力するだけの非常に簡単なサーブレット「TestServlet」を用意する。
これ自体は「.java」ファイルであり、つまり「ソースコード」なので、
Webアプリケーションとして動かすためにはこれをコンパイルして「.class」ファイルを作らなくてはならない。
この「.class」ファイルは(4)「WEB-INF」配下に配置するが、後述する。

なんとなく(4)「WEB-INF」の近くがいい、という理由からここに置いているが、
(1)htmlと違ってwarファイルに含める対象ではないので、
ここに位置している意味はまったくない。
全然違うローカルのエリアで管理しても構わない。

ちなみに↓のようなjavaファイルである。

import java.io.*;  
import java.text.*;  
import java.util.*;  
import javax.servlet.*;  
import javax.servlet.http.*;  

public class TestServlet extends HttpServlet {

private static final DateFormat LOG_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");  
  
private static final String PARAMETER_STR = "param";  
  
public TestServlet()  
{  
}  

public void doGet(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)  
	throws  IOException  
{  
	doProcess(httpservletrequest, httpservletresponse);  
}  

public void doPost(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)  
	throws IOException  
{  
	doProcess(httpservletrequest, httpservletresponse);  
}  

private void doProcess(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)  
	throws IOException  
{  
	printLog("★開始");  
	try  
	{	  
		Date startDate = new Date();  
		String param = httpservletrequest.getParameter(PARAMETER_STR);  
		  
		StringBuilder sb = new StringBuilder();  
		sb.append(LOG_FORMAT.format(startDate));  
		sb.append(" ");  
		if (param != null) {  
			if (param.equals("1")) {  
				sb.append("MODE=1");  
			} else if (param.equals("2")) {  
				sb.append("MODE=2");  
			} else if (param.equals("3")) {  
				sb.append("MODE=3");  
			} else {  
				sb.append("MODE=X");  
			}  
		} else {  
			sb.append("MODE=null");  
		}  
		  
		PrintWriter pw = httpservletresponse.getWriter();  
		pw.write(sb.toString());  
		pw.flush();  
		pw.close();  
	}  
	catch(IOException ioexception)  
	{  
		throw ioexception;  
	}  
	printLog("★終了");  
}  

private static void printLog(Object obj)  
{  
	StringBuilder stringbuilder = new StringBuilder();  
	stringbuilder.append(LOG_FORMAT.format(new Date()));  
	stringbuilder.append(" ");  
	if(obj != null)  
		stringbuilder.append(obj.toString());  
	System.out.println(stringbuilder.toString());  
}  

}

 




(3)warmakeフォルダ
warファイルを作るときに使うワークディレクトリ。
この配下に必要なものをかき集めて、後でwarにして固める。
(なので(1)と(4)が同じツリー構造でこの配下に出来上がっている)
詳細(A)で解説する。




(4)WEB-INFフォルダ
Webアプリケーションのうち、実際の実行に用いられる資産群。
なんか通例的に「WEB-INF」というディレクトリを使うらしいが、
これ自体は詳細省く(というか解説できん)。

ファイルとしては以下3点が格納されている。

  1. WEB-INF/web.xml
  2. WEB-INF/classes/TestServlet.class
  3. WEB-INF/lib/j2ee.jar

うち、2.の「WEB-INF/classes/TestServlet.class」は、
(2)sourceフォルダ配下のjavaファイルをコンパイルしたのを配置する。
1.と3.は自前で用意する。

1.にはいろいろ設定できるが、
とりあえずテスト用としてはサーブレットマッピングだけで十分である。
以下のような内容で記述して保存する。

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
 "http://java.sun.com/dtd/web-app_2_3.dtd">  

<web-app>
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>TestServlet</servlet-class>
</servlet>

&lt;servlet-mapping&gt;  
	&lt;servlet-name&gt;  
		TestServlet  
	&lt;/servlet-name&gt;  
	&lt;url-pattern&gt;  
		/TestServlet  
	&lt;/url-pattern&gt;  
&lt;/servlet-mapping&gt;  

</web-app>

 




(A)warmake.bat
これを一発叩くと(B)warファイルが出来上がるように仕組んであるbatファイル。
この位置(ルート直下)に配置されている前提で、以下のコマンドで記述された一連の処理を実行し、
warファイル作成までを行ってくれる。

@echo off  

rem 1.javaソースをコンパイルして、WEB-INF\classes配下に出力する
echo Javaソースコンパイル
javac -encoding UTF-8 -classpath %JAVA_HOME%;.\source;.\WEB-INF\lib\j2ee.jar; .\source*.java -d .\WEB-INF\classes\

rem 2.warmake自体とその配下を全部消して作り直し
echo warmake全削除と空フォルダ作り直し
rmdir /s /q .\warmake
mkdir warmake

rem 3.必要なものだけwarmake配下にコピーする
echo 必要な資産をwarmake配下にコピー
xcopy /y /s /e /i /q html warmake\html
xcopy /y /s /e /i /q WEB-INF warmake\WEB-INF

rem 4.jarコマンドでwarファイルをつくる
jar -Mcf wartest.war -C warmake/ .

pause


まず1.で、(2)sourceフォルダにあるjavaファイルをコンパイルし、(4)WEB-INFのclassesフォルダに出力する。
次に2.で、war作成用の作業用ディレクトリ(3)warmakeを根こそぎ削除し、空フォルダとして作り直す。
次に3.で、(1)htmlと(4)WEB-INFを(3)warmake配下にディレクトリツリー構造含め丸ごとコピーしてくる。
最後4.で、jarコマンドを使ってwarファイルに固めて、作成された(B)warファイルを同階層に出力する。

ちょっとググればすぐ出てくるが、
warファイルの実態はただのzipファイルなので、
jarを作るのと同じやり方で作成することができる。
違うやり方でも作成できるのだが、一番手っ取り早いのはjarコマンドで固めてしまうことである。
その際、デフォルトでくっつくマニフェスト(META-INF)を除くため、「-M」オプションを付与するが、
これはあまり重要ではない(別にマニフェストがあっても支障はない)

今回のような小規模なアプリでは、(2)sourceフォルダ配下は1ファイルしかなかったが、
普通のWebアプリでソース1ファイルなんてことはまず有り得なく、
実際には数百数千のソースコードを相手にコンパイルが必要になる。
この場合、パッケージ構造等を加味しても、
↑のbatファイルで記述しているコンパイルのコマンド(1.の部分)では大分無理があることは必至で、
何らかの方法を考えなくてはならない。
その対策として、build.xmlを用意してantに食わせるやり方がよく知られているが、ここでは割愛する。

まあとにもかくにも、こんな感じで出来上がった(B)wartest.war、
jarコマンドで作ったこともあって、tオプションで中身が見れる。
実際中身を見てみると↓のような感じに仕上がっている。

     0 Fri Jan 26 19:05:52 JST 2018 html/  
   763 Fri Jan 26 18:16:18 JST 2018 html/Test.html  
     0 Fri Jan 26 19:05:52 JST 2018 WEB-INF/  
     0 Fri Jan 26 19:05:52 JST 2018 WEB-INF/classes/  
  2228 Fri Jan 26 19:05:52 JST 2018 WEB-INF/classes/TestServlet.class  
     0 Fri Jan 26 19:05:52 JST 2018 WEB-INF/lib/  
1726123 Thu Jan 15 16:21:46 JST 2015 WEB-INF/lib/j2ee.jar  
   458 Fri Jan 26 16:18:12 JST 2018 WEB-INF/web.xml  

これにて、必要なものだけが詰まったWebアプリケーションアーカイブが完成したのだ!




こうして出来上がった(B)wartest.warを、
tomcatのwebapps配下にコピーしてtomcat起動すれば、
あとは勝手にWebアプリケーションとして展開してくれる。楽ちん。

 



一つ気を付けなくてはならないのは、この後tomca起動すると、
以下のように、「wartest.war」が解凍されたフォルダが直下に1つ出来上がる。

 



このフォルダがあると以後はそっちが優先して読み込まれてWebアプリケーションが立ち上がる。
なので、例えば「TestServlet.javaを修正して再コンパイルしたので、もう一度tomca再起動!」ってやりたい場合、
↑の手順に従ってwarファイルを再作成してwebapps配下のwarファイルを書き換えても、
このwebapps配下にある「wartest」フォルダを最新化しない限り修正は反映されない。
もし修正を反映させるなら、webapps配下の該当フォルダ自体を丸ごと削除して、warファイルを上書きして再起動するのだ。
(そうすると修正後のwarファイルを解凍してから起動してくれるので、修正内容が反映される)




で、無事にtomcatが立ち上がったら、
ブラウザを立ち上げてURLに「http://localhost:8080/wartest/html/Test.html」と入力してみる

 



テキストボックスに適当な値を入力して「送信」ボタンをクリックすると、
サーバ側の「TestServlet」が呼び出されて、レスポンスが表示される。

 



基本的にはこの流れでwarファイル作成とWebアプリケーション配備が可能である。




↑で述べたとおり、
現実的に運用されている/稼働しているWebアプリケーションのほとんどは、
大小さまざまなJavaクラスで構成されており、
実際のところこんな簡単なWebアプリケーションなど存在しない。
どちらかというと「ちょっとした検証」のために用いる、
という手法のための意味合いが強いと思う。
(個人的にもその用途である)
Webアプリケーション全体を用意するのは骨がおれるので、
検証したい箇所だけに限定した簡単なサーブレットを用意してテストする、というような目的。
その点では、このやり方でのWebアプリケーション作成とテスト方法は、
個人的には割と重宝している。


COMMENT:
kooさん>
返信に遅くなってしまい申し訳ありません、コメントありがとうございます。
そしてお役に立てたなら良かったです。
そうですね、この記事自体は若干古い環境で作ってるので、今はもうj2ee.jar単品では手に入らないかもしれません。javax.servlet.*が入ってるならservlet-api.jarでも問題ないと思います。


COMMENT:
AUTHOR: koo
DB接続確認のアプリを作るときとても参考になりました。文中のj2ee.jarはネットで見つけられず、Tomcat標準のservlet-api.jarで代替できました。