Struts1 [サンプルWebアプリ]

struts を使ったサンプルアプリを実際に作ってみます。bbs.jsp というページを作り、その中のフォームから テキストを送信します。送信後には再びbbs.jsp がクライアントに返されます。bbs.jsp はたった今おくられた テキストをテキストボックスに設定し、またテキストボックスの下にも表示します。
更新日 2016-02-13

まず雛型を配置

まず雛型(struts-blank.war)をTomcat 配下のwebapps ディレクトリにコピーします。Tomcat が起動していると 勝手にディレクトリ展開されてしまうので、止めておきましょう。なおファイル名はbbs00.war に変えます。 Tomcat を再起動すると、ファイル名に沿ったディレクトリ名で展開されます。
これが今回作成するサンプルのディレクトリになります。ブラウザでhttp://localhost:8080/bbs00/ にアクセスしてWelcome 画面を確認出来れば成功です。では再びTomcat を停止させます。
この点はstruts - インストールと同じ話です。

設定ファイルを変更する。

/bbs00/WEB-INF/struts-config.xml という設定ファイルを編集します。 ルートであるstruts-config エレメント内の子要素を順に見てゆきましょう。

data-sources エレメント

struts 1.1 までは有効だったデータソースに関する項目です。struts 1.2 以降ではデータソースは非推奨となりました。 何か書くとエラーになります。データベースへのアクセスに関してはstruts [データベース]をご覧下さい。

form-beans エレメント

ココに使う予定のアクションフォームを設定します。新規にform-bean エレメントを作成し、 name 属性にインスタンス名、type 属性にはアクションフォームのクラス名を指定します。 実際のインスタンスは、struts フレームワークによって作成されます。
<form-beans>

	<!-- 追加	-->
	<form-bean name="bbs_af"
				  type="mypackage.bbsActionForm" />
</form-beans>

global-exceptions エレメント

ココでは例外発生時の、一般ユーザー向けのページへフォワードする際の設定をします。 デフォルト設定でいいので、スキップ。

global-forwards エレメント

ページの転送設定ですが、必要ないのでスキップ。

action-mappings エレメント

ココに追加するaction エレメントに、リクエストに対応するアクションフォーム、 アクションクラス、レスポンスページなどの設定を記述します。一つのaction エレメントが、 一つのURLパス(リクエスト)に対応します。
<action-mappings>
	
	<!-- 追加	-->
	<action	path="/bbs"
				type="mypackage.bbsAction"
				name="bbs_af"
				scope="requuest"
				validate="false">
		<forward name="success" path="/bbs.jsp"/>
		<forward name="error" path="/error.html"/>
	</action>
</action-mappings>
action エレメントにおいて、@type, @name, @scope, @validate の各属性にはそれぞれ アクションクラスのクラス名、アクションフォームのインスタンス名、生存スコープ空間、検証の有無 を指定します。
今回は、リクエスト(つまりクライアントのフォームの送信先)が/bbs00/bbs.do の場合に 応答する事を示しています。ちょっとややこやしいけど、bbs00 というパスに配置された Webアプリであり、末尾に.do を付いたリクエストはアクションとして処理するのがstruts フレームワーク のデフォルト設定ですので。例えば、
http://localhost:8080/bbs00/bbs.do
とブラウザのアドレスバーに打つと、このアクションが応答しbbs.jsp (もしくはerror.html)が画面に出るという 訳です。

以降のエレメント

特に注視する必要も無いようなので、設定は終わりにします。

Java クラスの作成

実際にクラスのソースであるjava ファイル(*.java) を書き、実行バイナリであるクラスファイル(*.class) を コンパイルして生成します。

アクションフォームクラスを作成

リクエストデータ(クライアントのフォームからPOST されたデータ)を自動で格納する独自の アクションフォームクラスを作成します。 /WEB-INF/classes にbbsActionForm.java というファイルを新規作成し、ActionForm から派生させた だけのクラスを定義します。
// Compile command. You must be current file's directry.
// javac -classpath "../lib/struts.jar;../../../../common/lib/servlet-api.jar;"
 -d "." bbsActionForm.java

package mypackage;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public class bbsActionForm extends ActionForm
{
	private String m_str = "";

	public void setStr( String value)
	{
		this.m_str = value;
	}

	public String getStr()
	{
		return this.m_str;
	}
}
ファイル先頭にコメントアウトしてあるコンパイルコマンド(もちろん一行)でコンパイルします。 エラーが出なければ成功です。mypackage ディレクトリができて、その中にクラスファイルが出来上がります。
アクセサメソッドはget(set) + プロパティ名(先頭は大文字)と書きます。アクションフォームは格納の為だけの クラスと考え、不必要なメソッドや処理を実装しないようにしましょう。機能的な処理はアクションクラスで 行います。

アクションクラスの作成

アクションフォームへのリクエストデータ格納後、 アクションサーブレットからインスタンス化されてexcute() メソッドがコールされる アクションクラスを作成します。 /WEB-INF/classes にbbsAction.java というファイルを新規作成し、 以下のクラスを書きます。
// Compile command. You must be current file's directry.
// javac -classpath "../lib/struts.jar;../../../../common/lib/servlet-api.jar;"
 -d "." bbsAction.java

package mypackage;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class bbsAction extends Action
{
	public ActionForward execute
	(
		ActionMapping mapping,
		ActionForm form,
		HttpServletRequest req,
		HttpServletResponse res
	)
	throws Exception
	{
		// アクションフォームにアクセスできます。
		bbsActionForm myForm = (bbsActionForm)form;

		String str = (String)myForm.getStr();
		if (str.length() == 0)
		{
			return mapping.findForward( "error" );
		}
		else
		{
			return mapping.findForward( "success" );
		}
	}
}
引数で渡されるform はダウンキャストして使えます。
return では、struts-config.xml で書いたaction-mapping エレメント内の forward エレメントをname 属性で探し出し、ActionForward オブジェクトとして返しています。 (素直にreturn "error"; と書かせないとこが、フレームワークならではです。)
これもコンパイルしておきます。

ページの作成

実際に画面に表示されるbbs.jsp とerror.html を作成します。

bbs.jsp

bbs.jsp は送信前の画面でもあり、送信後の画面でもあります。CGI ではこうは行きません。bbs.jsp 内には スクリプトレットと呼ばれるサーバーサイドで実行されるスクリプトを書けるので、一部の値を動的に 反映する事ができます。さらにスクリプトレットの代わりとなるタグライブラリを用いています。
<%@page contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>

<html:html locale="true">
	<head>
		<title>bbs.jsp</title>
	</head>
	<body>
		<div>
			<html:form action="/bbs" method="POST">
				<html:text property="str" size="20" />
				<html:submit property="submit" value="実行" />
			</html:form>
		</div>
		<pre><bean:write name="bbs_af" property="str" scope="request" /></pre>
	</body>
</html:html>
実際にはJava で書き換えられコンパイルされるのですが、開発者にそれを意識させない点がJSP の魅力です。 動的に変化しうる返信ページを静的ページと同じようにHTML 文で書ける。タグライブラリにより、完全に スクリプトレスになった訳です。
page ディレクティブによって文字コードを柔軟に設定できます。pageEncoding はJSP 自体がどんな文字コードで 書かれているかをJavaコンパイラに指示し、contentType にはコンパイル後のJava クラスが出力する文字コードを 指定します。
(例えばWindows で保存したJSP ならpageEncoding にはShift_JIS(もしくはWindows_31J)を設定します。 ブラウザからのアクセスに対しては文字コードUTF-8 で出力したいというのであれば、contentType にcharset=UTF-8 と 設定すればOKです。)
html:form は<form name="bbs_af" method="POST" action="/bbs00/bbs.do"> に置き換えられます。name 属性にはアクションフォームのインスタンス名になって、 action 属性のパスが適切なモノに変わっている点に注目ください。これはつまり、bbs.jsp をただ リクエスト(GET)しただけにも関わらず、内部的にはaction-mapping の設定を調べて該当する アクションフォームを探し出し、インスタンス化までした事を意味しています。
html:form が仮に無い場合、このインスタンス化は行われず、bean:write はアクションフォームインスタンス(bbs_af) を 解決できずに例外発生となります(@ignore="false" で例外でなく無視させる事もできます)。html:form 下にネストされた html:text においてはインスタンス名を省略してプロパティstrにアクセスできてます。
[注) インスタンス化だけならjsp:useBean を使ってもできます。]
さらにクライアントのブラウザがCookie を無効にしている場合には、 action="/bbs00/bbs.do;jsessionid=BC7C9F43D15DD894D1D23F7E69DD50C1" のようにセッションID が 自動添付されます。この機能により、クライアントを気にせずセッション機能を使えるのがStruts フレームワークの真骨頂 です。この素晴らしい自動機能を使う為にはhtml:form というタグライブラリを使う事が必須となります!!

error.html

通常のhtmlページです。あえてjsp にしないでおきました。
<html>
<head>
	<title<error.html>/title>
</head>
<body>
	<h3<Error>/h3>
	<a href="bbs.jsp"<bbs.jsp に戻る>/a>
</body>
</html>
今回は値チェックをアクションクラスでリクエストパラメータの検証を行ってerror.html へ誘導していますが、 この手の検証もstruts には実装されています。次項のVaridator を参考ください。

実行

ではTomcat を再起動して($CATALINA_HOME/bin/shutdown.sh, startup.sh)、 http://localhost:8080/bbs00/bbs.jsp でアクセスします。エラーが出なければ成功 です。データを打ち込むと、過去の打ち込みデータがどんどん蓄積されてpre エレメント中に 表示されてゆくはずです。セッションが失われるまでデータは保持されます。
bbs00.war 今回のサンプルです。