@IT > Java Agile > 連載:現場に活かす Jakarta Project 第12回
 

第12回 フリーのStruts IDEによるWebアプリケーション開発

岡本隆史
(株)NTTデータ 技術開発本部/Ja-Jakarta Project PMC

2003/11/


 Jakartaプロジェクトにおいて、サーブレットコンテナであるTomcatと双璧を 成すのが、MVCフレームワークのStrutsです。Strutsを利用することにより、 Webアプリケーションを簡単にMVCモデルで開発できるようになります。 本稿ではStrutsを利用するメリットとその仕組み、ほかのアプリケーションとの 連携、 そして、無償で利用できる(残念なが らオープンソースではありませんが)Strutsの統 合開発環境 Exadel Struts Studio Community Edition を用いたグラフィカル なWebアプリケーションの開発について紹介します。

 本記事でのStrutsの解説は概要となりますが、Strutsについてより詳しく知りたい場合は、Ja-Jakartaプロジェクトの阿島氏の著書Jakartaプロジェクト カンタンStrutsをお勧めします。 なお、11月出版予定の拙書「Javaオープンソース徹底攻略〜 Eclipse/JBoss/Strutsから最新のXML/Webサービス技術まで〜」でも簡単に触 れていますので、こちらも参照して頂ければ幸いです。

  Strutsの仕組みとその周辺技術

 さて、Strutsの解説を行う前に、まず、MVCモデルを用いない場合の問題点を 見てみましょう。MVCモデルを用いない開発は、JSP Model1と呼ばれており、 このJSP Model1による開発は、JSPの中にロジックを埋め込み、遷移先をJSP自身に記述します。この方式でシステムを作成すると、図1のイメージになります。 

 

図1 JSPによる開発

ページからページへ遷移し、何のロジックを何処で実行するか、ページに全て記述しています。

 このモデルでは、次のような問題があります。

(1) ロジックを確認するために、画面のコード(JSP)を読む必要がある。
(2) ページ遷移が複雑になったときに、ページ遷移状況を確認するためには、各ページのコードを順番に追う必要がある。

 JSPには、タグライブラリと呼ばれる機能が用意されており、このタグライブ ラリとJavaBeansを組み合わせてロジックを記述すると、JSPにコードを記述す る必要はなくなり、タグを挿入だけでよくなります。このタグライブラリを利 用すると(1)は緩和されますが、どのロジックが実行されているか知るには、JSPの中身を確認する必要があります。また、(2)はそもそも解決できません。

  比較的小規模のシステムの場合、この方法でうまく設計/実装することができ ます。ただし、ページ数が増えると、図1は蜘蛛の巣のような構造になっ てしまい、コードを追うことによりページ遷移を確認するのは困難になります。

Struts 〜MVC Modelへ〜

 これに対して、モデル、ビュー、コントローラにコンポーネントを分けて開発 するMVCモデルをWebアプリケーションに最適化したMVC Model2を適用したJSP による開発スタイルは、JSP Model2と呼ばれています。Strutsをベースとした MVCモデルに移行すると、開発者が意識するコードは図2のようなイメージと なり、各ファイルの役割がすっきりします。

図2 Strutsによる開発

 ページの遷移情報はStrutsの設定ファイルであるstruts-config.xmlに集約さ れ、ロジックと画面が明確に分離できます。以下、詳しくみていきましょう。

画面
JSPもしくはVelocityのテンプレートが利用できます。最も普及しているJSPを 利用する場合は、ロジックの実行結果を表示するために、タグライブラリを利 用します。また、Velocityを利用する場合は、Velocity Toolsを利用します。

COLUMN  
StrutsでVelocity

最近リリースされたVelocity-Toolsを利用すると、JSPより、より直感的なテンプレートエンジンVelocityを利用することもできます。Velocityについては、今までは日本で利用される機会はあまりありませんでし たが、日本におけるサーブレットの第一人者である原田洋子氏の活動のせいもあり、序所に普及の兆しを見せています。最近、Ja-JakartaプロジェクトでもVelocityの翻訳プロジェクトのコミッタが増員されたので、今後の展望に期待したいところです。

画面遷移情報
各画面のフォームがsubmitされたときに実行するロジック、ロジックの実行結果、どのページに遷移するかといった、画面遷移情報をstruts-config.xmlに記述します。

ビジネスロジック実行
ビジネスロジック(以下、ロジック)は、アクションクラスから呼び出し実行し ます。アクションクラスでは、ロジックの実行結果を受けて、次に遷移する画面を決定します。アクションクラスはMVCモデルにおけるコントローラとモデ ルの間に位置していますが、ユーザーの実装によって、どちらにもなります。ロジックJavaBeansやEJB等を利用して提供し、アクションクラスでは、ロジックを実行するBeanの呼び出しとロジックの実行結果から次に遷移する画面を決定するコードのみを埋め込み、コントローラとして実装した方が設計上、コント ローラとモデルを明確に分けることができるのでよいでしょう。

入出力情報
フォーム情報/ロジックの実行結果はフォームBeanを利用してやり取りされま す。フォームBeanは、通常アクションクラスとペアになっています。このフォー ムBeanは、Struts1.0まではユーザがクラスを作成する必要がありましたが、 Struts1.1からはDynaFormBean(入力値の妥当性検証なし)や DynaValidatorForm(入力値の妥当性検証あり)が提供されているため、struts-config.xmlで、プロパティ情報を定義さすれば、ユーザがBeanを作成する必要がなくなりました。

入力値の検証情報
Strutsでは、ユーザがフォームに入力した値を検証するValidatorを利用すると簡単に入力値のチェックを行うことができます。struts-config.xmlに必要な設定を行い、郵便番号、メールアドレス、数字などに対する検証情報を定義 したvalidator-rule.xmlと、Webフォーム(フォームBean)のどのフィールドを検証するか設定したvaliation.xmlを用意することで、Validatorを利用できます。

アプリケーションリソース
メッセージやエラーメッセージをアプリケーションリソースとして定義します。 Validatorによる入力値の検証を行う場合は、エラーメッセージをアプリケー ションリソースで定義する必要があります。

 StrutsはWebアプリケーションを開発するための上記のエッセンスを提供して いますので、簡単にWebアプリケーションを開発できるようになります。それと同時に複雑な構成なWebアプリケーションを予防することもできます。

Strutsの提供しない機能

 Webアプリケーションを開発するには、MVCのような設計思想だけを考慮すればよい訳ではなく、そのほかに様々な機能が必要となってきます。ここでは、Strutsを利用する場合、他に必要なアプリケーション、あると便利なアプリケー ションを紹介します。

ユーザ認証
Strutsの機能を利用して、ログイン画面を作成することもできます。Strutsの サンプルの中には、ログインのサンプルなどを紹介している例もありますので、 Strutsの機能を利用する上で最も簡単に実現できる機能です。認証の機能については、JAASやレルム機能を利用する方法もあります。JAASやレルムを利用すれば、BASIC認証やFORMベース認証等の認証方法の選択、データベース、LDAP、 ファイル等、ユーザ認証情報の保存先の選択、コードレスの認証等の利点があるので、可能であれば、アプリケーションサーバの機能を利用した方が良いで しょう。

暗号化
クレジットカード番号等を扱うショッピングサイトなどではメッセージを暗号化していますが、暗号化の部分には、ApacheとApacheをSSL(TLS)対応にするmod_sslモジュールを組み合わせたり、アプリケーションサーバのSSL機能を利用します。ハードウェアSSLアクセラレータを利用することもあるでしょう。

データベースとの連携
データベースとの連携は、JDBCを利用して行うこともできますが、最近では、データベースのテーブルとJavaオブジェクトを透過的にマッピングし、JDBCを利用したコードを記述することなくJavaオブジェクトを簡単にデータベースにWrite/ReadできるCMPやO/Rマッピングツールが良く利用されています。CMPと O/Rマッピングツールを比較すると、CMPの方が永続化フィールド毎にトランザ クションやセキュリティを細かく制御できるといったメリットがありますが、最近はCMPはパフォーマンスが悪い、フィールド毎の細かいトランザクション 制御が必要な局面が少ないということで、Torque、Hibernate、JDO等のO/Rマッ ピングツールが注目を浴びています。

トランザクション制御
上記のデータベースの連携と深く関係してきますが、データベースを利用する場合は、一連の処理をトランザクションで実行する必要があります。JDBCドライバを直接利用する場合は、データベースを読み書きするコネクションをうまくトランザクションの中で使いまわす必要があります。

EJBを利用する場合は、SessionBeanを利用して、Facadeパターンを用いてトラ ンザクション区間の処理をラッピングしてもよいでしょう。また、JDBCを著説利用する場合や、JavaオブジェクトとRDBMSのテーブルをマッピングするO/Rマッピングを利用する場合などは、JTAを利用します。J2EEアプリケーションサーバを利用する場合は、JTAの機能を提供しているので、簡単にJTAを利用できますが、Tomcatを用いる場合は、オープンソースのJTM実装であるJOTM/Tyrex等を利用することになります。これらを使えば簡単にトランザクション区間を設定できます。

  Struts StudioによるWebアプリケーションの開発

 さて、実際にStrutsを使ってWebアプリケーションを作成してみましょう。ここでは、数当てゲームを例にSrtutsでアプリケーションを作成します。

(1) スタート画面:ユーザは最初、ユーザ名と数字を入力
(2) 入力値判定:サーバ中で発生させた乱数とユーザが入力した数字を比較
  数字が不正解の場合:その数字がサーバ内の数字より大きいか小さいか画面に表示し、数字の入力を求める。
  数字が正解の場合: 正解メッセージを表示し、ゲームを終了
(3) 例外処理Exception発生時:例外処理を行い、エラー画面を表示

  これで、条件分岐と例外処理等、一通りStrutsの機能を利用するアプリケーショ ンを作成することができます。ここでは、この数当てゲームをStruts Studio で作成します。Struts Studioを利用すると、図3のようにGUIで画面遷移を定義することができ、直感的な開発を行うことができます。

図3 Struts Studioによる開発画面

Struts Studioの特徴

 筆者は、Strutsを利用するのが非常に億劫でした。まず、インストール方法がよく分からなかったり、やっとインストールできても、struts-config.xmlの 書式を理解するのが面倒だったり、なんとかstruts-config.xmlを作成しても、 JSPやロジックを実行するアクションクラスに埋め込んだ値と整合性が取れず エラーが頻出したりと、とにかく頭が痛いフレームワークでした。しかし、 Strutsを利用したアプリケーションを開発するために生まれたIDE Struts Studioを利用して筆者の考えは変わりました。ここで利用するStruts Studio には、次のような特徴があります。

迅速な開発環境の構築
ワンクリックでStruts Studioをインストールするだけで、StrutsからTomcatまで、Strutsの開発環境を整えることができます。

TomcatによるJust In Time実行
付属のTomcat上でStruts Studioで作成したStrutsアプリケーションを即座に実行することができます。また、編集した内容も即座にTomcatに反映することができ、開発とテストをシームレスに行うことができます。

GUIによるstruts-config.xmlの作成支援
GUIでお絵描き感覚で画面遷移を記述したり、グラフィカルなツリービューで、struts-config.xmlの設定を行うことができます。struts-config.xmlをエディタで編集して開発した場合、typo等の入力ミスによるエラーに悩まされますが、StrutsStudioを利用すれば、そのようなミスを減らし開発効率を向上することができます。

クラステンプレート生成機能
struts-config.xmlの情報をもとに、アクションクラス等のテンプレートを生成します。ユーザは、テンプレートにロジックを実装するだけでよくなり、余分なコーディングの手間を省けます。

テンプレートによるJSPタグライブラリの入力支援
JSPのテンプレートを豊富に用意しており、タグライブラリの入力をスムーズに行うことができます。

Antによるビルド機能
Struts Studioで作成したプロジェクトに対し、自動的にAntのビルドファイルが生成され、Struts Studioでコードをコンパイルする際にはこのビルドファイルが利用されます。Antを使うことにより、Struts Studioを利用しない環境でもアプリケーションを簡単にビルドすることができます。

英語版のみ提供
現在は、英語版しか提供していません。しかし、メニューやヘルプメッセージが英語というだけで、日本語の入力出力も可能となっています。一部、プロパティファイルをnative2asciiでunicodeエスケープに変換する必要がある等、制限はありますが、日本語環境でも問題なく利用できます。


 Struts Studioには、Community Edition/Standard Edition/Professional Editionが用意されており、Community Editionは無料(注) で利用可能となっています。

注:ExadelのWebサイ トではfreeとしか書いていなかったので、コマーシャルプロダクトの開発に利 用可能かどうか問い合わせたところ、利用できるという返事を頂きました。

準備

(1)インストール

 ExadelのStruts Studioの配布サイトhttp://www.exadel.com/products_strutsstudio.htmからStruts Studio Community Editionをダウンロード、インストールします。ダウンロードにはユーザ登録が必要なので、注意してください。Struts StudioはWindows版と Linux版が用意されていますが、ここでは、Windows版を用いて解説します。Struts Studioの起動は、Windows版の場合は、スタートメニューから「Struts Studio 4.7 with Console」を選択することで起動できます。Struts Studioの画面を簡単に解説すると、図4のようになります。

図4 Struts Studioの画面

ナビゲーションパネル
Webアプリケーションのディレクトリやstruts-config.xmlの要素等をツリーで閲覧することができます。

プロパティビュー
上記ナビゲーションパネルで選択したファイルの属性等を表示/入力します。

ダイアグラムビュー
struts-config.xmlをグラフィカルなダイアグラムで表示します。このビューを用いて画面遷移を定義します。

パレットバーマクロ
JSPのタグライブラリの入力を支援します。様々なテンプレートが用意されており、簡単にタグを入力することができます。また、ユーザー定義のタグを追加することも可能です。

コンソール
TomcatやAntのメッセージが表示されます。

Tomcatランチャ
Tomcatの起動や停止を行うことができます。図4の左から設定、起動、再起動、停止、web.xmlのタイムスタンプ更新(アプリケーションのリロード)となっています。


(2)プロジェクト作成

 Struts Studioは一般的なJavaのIDEと同じように、プロジェクトでアプリケーションを管理します。プロジェクトを作成するには、メニューの「File」→「Create New Project」を選択し、Nameフィールドにプロジェクト名を入力、 「Next」ボタンを押し、次の画面で「Finish」を押します。ここでは、プロジェ クト名に「guess」を入力します。

GUIで画面遷移作成

 Struts Studioで画面遷移を作成してみましょう。左のナビゲーションパネルからWEB-INF/struts-config.xmlをダブルクリックで選択します。すると、 ダイアグラムビューが表示されます。ダイアグラムビュー上で右クリックし、 メニューからAddを選択すると、次のメニューが表示されます。

図5 Addメニュー画面

表1 Addメニュー
メニュー 解説
Action アクションの作成
Global Foward グローバルフォワードの作成
Global Exception グローバル領外への作成
Page JSPページの作成

 Struts Studioでは、この4つを作成しながら、画面遷移を作成することになり ます。では実際に数当てゲームの画面遷移を作成してみましょう。

(1)グローバルフォワードの作成

 まずグローバルフォワードを作成しましょう。グローバルフォワードは、Webアプリケーションの開始点です。ユーザーはまず、グローバルフォワードからリンクされた画面を最初にアクセスします。ここでは、Webアプリケーションが 開始すると数字入力画面/pages/start.jspを表示するグローバルフォワードを作成します。strutsコンフィグエディタ上で右クリックし、「Grobal Foward」 を選択し、表示されたダイアログ(図6)で次のように入力してください。

図6 グローバルフォワード作成ダイアログ画面

表2 グローバルフォワードの作成ダイアログ
項目 入力値 解説
name* start 名前
path* /pages/start.jsp 実行するパス
redirect リダイレクトの設定
contextRelative モジュールの設定

 ダイアログ右下のHelpを押すとダイアログの解説を英語で見ることができます。Okを押すと、ダイアグラムビューが図7のように変化し、struts-config.xmlへの設定追加と/pages/start.jspの生成を自動的に行います。

図7 作成されたグローバルフォワードとJSP

注:以降の説明ではプロパティ設定のダイアログの画面は省略します。

(2)アクション

  アクションは、ロジックの実行単位です。アクションの設定によりコントロー ラであるActionServletの動作を決めることになります。図8を用いて簡単に説明します。

図8 アクション

入力
JSPからアクションサーブレットを介してアクションが実行されます。アクセスするURLは*.doで表されます。

Webフォームの値を設定
アクションサーブレットは、送信されたPOST/GETのパラメータ情報をもとに、フォームBeanにWebフォームの値を設定します。

アクション実行

ロジックを実行するアクションクラスを呼び出します。アクションクラスは、画面の遷移先情報を返却します。

フォームBeanの参照、変更
アクションクラスの内部でフォームBeanの値を参照し、ロジックを実行します。ロジック実行中、必要であれば、フォームBeanの値を変更します。

フォワード
アクションサーブレットから、JSPへフォワードし、結果をJSPで出力します。他のアクション(アクションサーブレット)へフォワードし、別のロジックを実行することもできますが、最終的にJSPを介して画面を出力します。

 上記のフォームBean/アクションクラスの設定をここで行います。 

ダイアログビュー上で、右クリック「Add」→「Action」を選択し、現われたダイアログで、次のように入力します。

表3 フォームBean/アクションクラスの設定

フィールド 入力値 解説
name guessform フォーム名
path* /guess アクションが関連付けられるパス。アクションは、 *.doで表記されるURLに対応付けられる(ここの場合/guess.do)
scope session アクションフォームのスコープです。 session,requestを選択できます。
type GuessAction アクションクラスのクラス名
validate false Struts Valdatorにより、フォームの入力値の妥当 性検証を行うかどうか指定。

アクションが作成されると、ダイアグラムビューに次のように表示されます。

図9 アクション作成後の画面遷移

この情報は、左のナビゲーションパネルのstruts-config.xml/action-mappingsに も表示されます。ここで、ダイアログビューの/pages/start.jspにカーソルを合わせクリックし、今作成したアクションguessに線をドラッグする持っていくと次の図のようになり、start.jspのフォームを入力して、guessアクショ ンを実行させることができます。

10 guessアクショ ンの実行までの画面遷移

(3)フォワードの作成

 アクションを実行した結果、どの画面を表示するか、あるいは次にどのロジックを実行するかをフォワードで定義します。ここでは、次のように遷移先を設定します。

入力した数字が正解の場合 /pages/match.jsp
入力した数字が不正解の場合 /pages/unmatch.jsp

 先ほど作成したguessformと表示されたアクションのアイコンを右クリックし、「Create Forward」を選択して現われた画面で、必要な情報を入力します。例えば、matchには、次のように入力します。

表4 フォワードの作成(matchの場合)

項目 入力値 解説
name: match フォワード名
path: /pages/match.jsp フォワード先の情報
redirect: リダイレクトの設定
contextRelative: モジュールの設定

同じく「Create Forward」を選択しunmatchに、

表5 フォワードの作成(unmatchの場合)
項目 入力値
name: unmatch
path: /pages/unmatch.jsp
redirect:
contextRelative:

と入力します。

 2つのフォワードを作成すると、フォワード先のJSPが自動的に生成されます。最後に、unmatch.jspからguessアクションへリンクを張れば、数当てアプリケーションの画面遷移は完成します(図11)

図11 完成した画面遷移

モデルの実装

 さて、画面遷移が完了したら、アクションと画面の間で値をやり取りするフォームBeanとロジックを実行するアクションクラスを作成しましょう。

(1)フォームBeanの作成

 アクションクラスとJSPの間でパラメータをやり取りするためのフォームBeanを作成します。Struts1.0では、フォームBeanをユーザーがコーディングする必要がありましたが、Srtuts1.1から導入されたDynaFormを利用すると、アクションフォームBeanを作成する必要がなくなり、プロパティをセットするだけでよくなります。ここでは、後でユーザーの入力値の妥当性検証を行うことを考慮し て、DynaFormBeanに妥当性検証機能を追加したDynaValidatorFormを利用します。

(1)ナビゲーションパネルの/WEB-INF/struts-config.xml/form-beansを選択し、右クリック「Create FormBean」を選択します図12)(

注:以降、/XXX/YYYと記述した場合、ナビゲーションパネルのツリーの位置を表すこととします。 

図12 new-form.bmp

以降、表示されたダイアログで、

表6 フォームBean作成ダイアログ
項目 入力値
name* guessform
type* org.apache.struts.validator.DynaValidatorForm

と入力します。すると、ナビゲーションパネルのform-beansにguessformが生成されます。ここで一点注意がありますが、name*は、ダイアログビュー上のアクションの名前と同じにして下さい。

(2)このフォームBeanをDynaFormとして利用する設定を行います。ナビゲーションパネルのguessformを右クリック→「Properties」→「Advanced」タブを選択し、dynamicプロパティをtrueにします。

(3)フォームBeanで利用するプロパティを追加します。ナビゲーションパネルのguessformを右クリックし、「Create Form Property」を選択、表示されたダイアログで次のように入力します。

表7 フォームプロパティ作成ダイアログ
フィールド 入力値 名前
name num プロパティ名
type java.lang.String プロパティの型
initial 初期値
size サイズ

 上記のnumを利用して、JSPのフォームからの入力値の取得と出力値の設定を行います。さらに、ユーザの名前を取得するnameプロパティ(name:name、type:java.lang.String)と、ユーザーが入力した数字が大きいか小さいかロジックで判定した結果を入れるisGreaterプロパティ(name:isGreater、type:java.lang.String)を(3)を繰り返し定義します。

定義が完了すると、次のようになります。

図13 定義完了までの画面遷移

画面を見ると、一目でguessformにnum/isGreater/nameの3つのプロパティが定義されていることが分かります。

(4)次に、ナビゲーションパネルから「plug-ins」を選択、右クリックで「Create SpecialPlug-in」→「Valudators」を選択します。これは、DynaValidatorFormもしくは、ValidatorFormの固有の設定になります。

(2)アクションクラスの作成

アクションクラスでは、

・ロジックの実行
・ロジックの実行結果による次の画面の遷移先の決定

を行います。アクションクラスを生成するには、アクションを右クリックし、現われたダイアログに必要情報を入力します。

表8 アクションクラス作成ダイアログ
フィールド 入力値 名前
Action class GuessAction アクションクラス名
Base class: org.apache.struts.action.Action アクションクラスの基底クラス
Imports このアクションクラスでimportするクラス
Generate JavaBeaan porperties v JavaBeansのプロパティを生成
Generate contants for local forwards v グローバルフォワードのための定数生成
Generate constants for local forwards v ローカルフォワードのための定数生成
Output path* ソースを生成するディレクトリ

 設定が終わったらGenerateボタンを押します。すると、アクションクラスが生成されます。あとは、executeメソッドにロジックを実装します。エディタを用いた開発では、フォワード名とstruts-config.xmlの設定値と間違えてエラーが発生し、この誤りの原因を突き止めるのに苦労すると言ったことがありますが、Struts Studioで作成したアクションクラスには、struts-config.xml の情報をもとに、次のようにフォワード名が定義されるので、その心配はありません。

public class GuessAction extends org.apache.struts.action.Action {
    
    // Local Forwards
    private static final String FORWARD_match = "match";
    private static final String FORWARD_unmatch = "unmatch";

 アクションの実行内容は、次のようにexecuteメソッドに実装します。

GuessAction.java
   ...
    public ActionForward execute(ActionMapping mapping, 
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
            throws Exception

// フォームBeanのキャスト    
        DynaActionForm df = (DynaActionForm)form;// (1)

        // フォームから入力された数字を取得
        int num = Integer.parseInt((String)df.get("num"));// (2)
        HttpSession session = request.getSession();

        // HTTPセッションからgeneratedNumber属性を取得  
        Object o = session.getAttribute("generatedNumber");
        int generatedNumber;
        
        if(o==null) {
            // generatedNumber属性がnullであればゲーム開始とみなし、
            // 乱数を生成し、generatedNumberに設定
            generatedNumber = (int)(Math.random()*100);
            session.setAttribute("generatedNumber",
                                 new Integer(generatedNumber));
        } else {
            // 既にgeneratedNumberを生成済みであれば、値を取得
            generatedNumber = ((Integer)o).intValue();
        }

        if  (num!=generatedNumber)  {// 入力値と数字が異なる
            // num > valの結果をアクションフォームのisGreaterに設定
            df.set("isGreater", new Boolean(num>generatedNumber));// (2)

            // 不正解画面へ遷移するActionForwardを返却
            return mapping.findForward(FORWARD_unmatch);// (3)
        } else { // ユーザの入力値と数字が同じ
    // 属性を削除
    session.removeAttribute("generatedNumber");

    // 正解画面へ遷移するActionForwardを返却
    return mapping.findForward(FORWARD_match);// (3)
}
 
    }
...

 executeメソッドを実装する注意点としては以下の点が上げられます。

(1) フォームBeanのキャスト
フォームBeanをフォームBeanの作成で定義したクラスにキャストします。ここでは、DynaValidatorFormの親クラスであるDynaActionFormにキャストしています。
(2) フォームBeanから値の取得と設定を行います。ここでは簡単のためisGreaterというプロパティをフォームBeanに設定していますが、Webのフォームの入力値以外のユーザーが操作しない値は、generatedNumberのように HttpSessionの属性に設定してもよいでしょう。
(3) メソッドの戻り値にmapping.findForward(<フォワード名>)で返却されるActionForwardを返却します。このフォワード名により、次に遷移する画面もしくはアクションを指定します。
(4) メソッド内で発生したExceptionは、後で紹介するグローバル例外へ遷移させることができます。

ここでは、入力したソースコードは、左上にあるbuildアイコンから「build」を選択するとAntを利用してコンパイルできます。

図14 build-ant.bmp

(3)コントローラの設定

 HTTPヘッダのパラメータの設定、ブラウザから入力したリクエストを処理するリクエストプロセッサの設定等を行います。

 まず、日本語がブラウザ上で正しく表示されるようにHTTPヘッダのcontentTypeの設定を行います。ここでは、ナビゲーションパネルのWEB-INF/struts-config.xml/controllerを右クリック、「CreateProperty」を選択し、次の値を入力します。

表9 プロパティ作成ダイアログ
フィールド 入力値
property* contentType
value* text/html;charset=Windows-31J
initial
size

 次に、ブラウザからの日本語入力を正しく処理できるようにリクエストプロセッサを作成、登録します。リクエストプロセッサは、その名の通り、HTTPのリクエストを処理するクラスです。アクションの実行は、このリクエストプロセッサから呼び出されます。リクエストは、リクエストプロセッサのprocessメソッドを実行することにより行われますが、デフォルトのリクエストプロセッサorg.apache.struts.action.RequestProcessorを継承したクラスの直前にリクエストの文字コードを指定することで、文字化けを回避することができます。

 ナビげーションパネルの/srcを右クリック→「Create」→「File」 →「Java」でCharsetProcessorクラスを作成します。

CharsetProsessor.java

import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
import org.apache.struts.action.*;

public class CharsetProcessor extends RequestProcessor {

  public void process(HttpServletRequest request,HttpServletResponse response) 
          throws IOException,ServletException 
  {
    request.setCharacterEncoding("Windows-31J");
    super.process(request,response);
  }

}

 リクエストプロセッサを登録するには、ナビゲーションビューから、/WEB-INF/struts-config.xml/controllerを選択すると、controllerタグの属性が表示されるので、processorClassにクラス名CharsetProcessorを設定 します。設定が完了すると、図15のような画面になっているはずです。

図15 controllerの設定画面

なお、リクエストの文字コードの設定については、今後、リクエストプロセッ サを登録しなくとも文字コードを指定できるように改良したと考えています。

ビューの作成

(1)JSPの作成

  JSPの画面を作成します。ダイアグラムビューで、JSPをクリックす るすると、JSPエディタが起動します。このエディタで各JSPに対して、リスト xx、リストxx、リストzzのように入力します(bodyタグ等、解説に不要なタグは 省略しています)。

 StrutsのJSPでは、通常のHTMLタグの代わりにhtml:xxxタグやlogic:xxx、bean:xxxタグを利用してJSPを作成します。これらStruts固有のタグを利用することにより、URLを適切なパスに展開したり(html:form)、簡単な条件分岐や値チェックを行ったり(logic:xxx)、Webブラウザのフォームで入力した値をフォームBeanに対応付けたり(html:text)、フォームBeanのプロパティの値を表示したり(bean:write)することができます。

リスト:start.jsp
<%@page pageEncoding="Windows-31J"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:html>
<html:form action="/guess.do">
お名前と数字を入力して下さい。<br/>
お名前:<html:text property="name"/><br/>
数字:<html:text property="num"/><br/>
 <html:submit value="送信"/>
</html:form>
</html:html>

リスト:unmatch.jsp
<%@page pageEncoding="Windows-31J"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html>
<html:form action="/guess.do">
<!-- 名前を表示 -->
<bean:write name="guessform" property="name" />さん:
<!-- idGreaterが設定されていればメッセージを表示 -->
<logic:present name="guessform" property="isGreater" >
<logic:equal name="guessform" property="isGreater" value="true">
もっと小さい数字
</logic:equal>
<logic:equal name="guessform" property="isGreater" value="false">
もっと大きい数字
</logic:equal>
を入力して下さい。
</logic:present> <br />
<html:text property="num" />
<html:submit value=" 送信" />
</html:form>

</html:html>

リスト:match.jsp
<@page pageEncoding="Windows-31J"%>

<html:html>
あたりです。おめでとうございます。
</html:html>

(2)アプリケーションリソースの設定


  アプリケーションリソースは、エラーメッセージ等のメッセージを記述するプロパティファイルです。アプリケーションリソースは後で利用しますが、これを設定しておかないとStrutsが動作しないので、設定を行います。WEB-INF/struts-config.xml/resourcesを選択、右クリック「Define Message Resources」を選択し、ダイアログで、

parameter*: ApplicationResources

と入力し、Okを押します。

実行

 さて、準備ができたら、アプリケーションを実行してみましょう。左上の Tomcatランチャから左から2番目の三角のアイコンをクリック すると、Tomcatを起動します。Tomcatの起動の様子は下のコンソールに表示されます。 Tomcatが起動したら、グローバルフォワード(ここでは、「start」のアイコン) を右クリックしてrunを選択するだけで、ブラウザが起動し、Webアプリケーショ ンを実行できます。

図16 Tomcatランチャ画面

図17 グローバルフォワード画面

 Actionクラス等のコードを変更した場合は、Tomcatランチャの一番右の手のア イコンををクリックすると、Webアプリケーションがリロードされ、Tomcatを 再起動することなく更新したアプリケーションでテストできます。

エラー処理と妥当性検証

 さて、先ほど作成した数当てゲームは、例外処理が入っていませんでした。これに例外処理を入れてみましょう。Strutsには、次の2つの例外処理機構があ ります。Strutsは、エラー処理として次の2つをサポートしています。

フォーム入力値のエラー
Webフォームの数値を入力すべきフィールドにアルファベットを入力した場合などの、フォームに入力した値が不正な場合のエラー処理。

Exceptionによるエラー
ロジック実行中に発生したExceptionに対するエラー処理

 それぞれ具体的に見ていきましょう。

(1)フォーム入力値のエラー

 Struts Validatorを利用すると、フォームの入力値の妥当性検証を簡単に行うことができます。また、検証方法もクライアントサイドの検証とサーバサイド の検証を同時に行うことができます。妥当性検証を行うには、ValidatorFormを継承したフォームBeanを用いるか、DynaValidatorFormを利用する必要があります。既にDynaValidatorFormを利用しているので、ここでは、validationの設定方法を説明します。

(1)妥当性検証ファイルvalidation.xmlを設定します。ナビゲーションパネル から/WEB-INF/validation.xmlをクリック、エディタを起動し次の太字の部分 をformsetタグの後ろに追加します。

/WEB-INF/validation.xml
    <formset>
<form name="guessform">
            <field
                property="num"
                depends="required,short">
<!-- ApplicationPropertiesへの引数({0}) -->
                <arg0 key="guessform.num.name"/>
             </field>
        </form>

        ...

ここでは、guessformのnumプロパティに対し、値の入力が必須(required)で、short型の数値(short)という条件で検証の条件を設定しています。

(2)次に、エラーメッセージ等のメッセージを記述するアプリケーションリソースを準備します。ここでは、ナビゲーションパネルの「src」ディレクトリ を選択し、右クリック→「Create」→「File」→「Properties」と選択し、 nameフィールドにApplicationResourcesを入力し、ApplicationResource.propertiesを作成します。そして、プロパティのnameとvalueをそれぞれ、次のように設定します。

表10 プロパティの作成

name value
errors.required {0}が空です。値を入力して下さい。
errors.short 数字を入力して下さい。
guessform.num.name 数字

図18 ApplicationResource.propertiesの画面

 ここで、先ほどのvalidation.xmlの次の行に注目して下さい。

                     depends="required,short">
<!-- ApplicationPropertiesへの引数({0}) -->
                <arg0 key="guessform.num.name"/>              

 上記の値は、requiredに対するエラーメッセージは、アプリケーションリソースの errors.requiredに、shortに対するエラーメッセージはerrors.shortに記述 します。また、errors.requiredに{0}という記述がありますが、これは、validation.xmlのarg0要素で指定されたアプリケーションリソース 「guessform.num.name」の値(「数字」)に対応づいています。

 プロパティは、unicodeエスケープで保存する必要がありますが、Struts Studioのプロパティエディタはunicodeエスケープに対応してません。そこで、コマンドプロンプトを起動し、C:\StrutsStudio\tomcat\webapps\hello\WEB-INFに移動し、次のように実行し ます。

                     > native2ascii src\ApplicationResources.properties classes\ApplicationResources.properties            

これで、プロパティファイルがunicodeエスケープに変換されてclassesディレ クトリに保存されます。

unmatch.jsp(赤字の部分を追加)
<%@page pageEncoding="Windows-31J"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html>

<html:javascript formName="guessform" />
<html:form action="/guess.do" onsubmit="return validateGuessform(this)">
  <!-- idGreaterが設定されていればメッセージを表示 -->
  <logic:present  name="guessform" property="isGreater" >
  
    <!-- 名前を表示 -->
    <bean:write name="guessform" property="name" />さん、

    <logic:equal name="guessform" property="isGreater" value="true">
      もっと小さい数字
    </logic:equal>
    <logic:equal name="guessform" property="isGreater" value="false">
      もっと大きい数字
    </logic:equal>
    を入力して下さい。
  </logic:present>
<br />
  <!-- numに対する妥当性検証のエラーメッセージを表示 -->
<html:errors property="num"/>
  <html:text property="num" />
  <html:submit value=" 送信" />
</html:form>

</html:html>

(2)アクションの設定


  ダイアグラムビューで/guessアクションを右クリックしてプロパティを表示し、次のようにプロパティを設定します。

表11 プロパティの設定

Name Value 解説
validate true Struts Valdatorにより、フォームの入力値の妥当性検証を行うかどうか指定。
input /pages/unmatch.jsp エラーが発生した時に遷移する画面

これで、guessアクションに対するサーバサイドの妥当性検証unmatch.jspに対するクライアントサイドの妥当性検証が有効になり ます。最初の画面で数字を入力する場所に数字以外の値を入力すると次のようにエラー表示されます。

図19 エラー画面

 また、unmatch.jspで数字以外の文字を入力すると、JavaScriptにより、次のようにエラーが表示されます。

図20 エラー画面

(3)システム例外

  アクションクラスの中で、ロジックを実行する際に発生したExceptionによりエラー用ページに遷移させることができます。DBエラー等のシステム障害が発生した場合には、この仕組みを利用するとよいでしょう。例外処理には、グローバル例外とローカル例外の2つの例外処理機構があります。グローバル例外は、全てのアクションで発生した例外を処理でき、ローカル例外は各アクションで発生した例外を処理するという違いがあります。Struts Studioを用いると、グローバル例外の作成を簡単に行うことができます。ダイアグラムビュー上で右クリック、Global Exceptionを選択し、表示されたダイアログで次のように入力します。

表12 グローバル例外の作成ダイアログ

フィールド 入力値 解説
key* errors.exception エラーメッセージ
type* java.lang.Exception Exceptionの型
path /pages/error.jsp 遷移先の画面
type GuessAction アクションクラスのクラス名
scope スコープ

 すると次のようになります。

図21 グローバル例外時の画面遷移

この遷移図がExceptionが発生した場合、/pages/error.jspを表示することは 一目でわかりますね。あとは、/pages/error.jspをクリックして次のように入力します。

error.jsp
<%@page pageEncoding="Windows-31J"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:html>
 <html:errors/>
</html:html>

 そして、エラーメッセージをApplicationResources.propertiesに追加します。

表13 エラーメッセージ

name value
errors.exception システム障害が発生しました。恐れ入りますが、現在サービスをご利用になることはできません。

 ApplicationResources.propertiesを編集したら、 先ほどと同じようにnative2asciiを利用して変換して下さい。

日本語環境の注意について

 既に日本語を利用する方法は本稿中で述べていますが、ここでまとめて見ましょ う。

(1)JSPファイルのpageディレクティブでpageEncodingを設定する。

<%@page pageEncoding="Windows-31J"%>

(2)controllerの設定でcontentType属性と RequestProcessorの登録を行う。

(3)native2asciiでアプリケーションリソースを unicodeエスケープ形式に変換する。

 もし、日本語が正しく扱えない場合は、これらの点に注意してみましょう。 また、Unix環境ではWindows-31Jの代わりにEUC-JPを利用するとよいでしょう。

  おわりに

 Strutsの基本とStruts Studioを利用したWebアプリケーションの開発について紹介してきました。Struts Studioを利用すれば、面倒だった struts-config.xmlの編集の必要がなくなり、初心者でも直感的にStrutsを利用できるようになります。Struts Studioは現在は英語版しかリリースされて いませんが、今後の日本語版のリリースに期待したいところです。

 最後になりましたが、残念ながら、本連載、現場で使えるJakartaプロジェクトは今回で最終回となります。総論からはじまり、Ant/Commons/Taglib/Tomcat WebDAV、そして、Strutsと紹介してきました。連載当初JakartaのプロジェクトであったAnt/Avaon/Jamesは個別プロジェクトへ移動し、Torque/OJBも新設されたApache DBプロジェクトへ移動しました。Turbineのコンポーネントの1つだったMavenも独立したプロジェクトとなり、Antに変わるビルドツールとして注目を浴びています。この1年は正にJakarta プロジェクトにとって激動の年といえるでしょう。また、サーバサイトJavaの オープンソースといえばJakartaでしたが、アプリケーションサーバのJBossや O/RマッピングツールのHibernate、メタデータによる新しいスタイルのプログ ラミングを提供するXDoclet、そして、爆発的な勢いで普及しているIDEのEclipse等、Jakarta以外にも使えるオープンソースは多数現われています。 一昔前はJavaのオープンソースと言えば、Jakartaでしたが、そのような時代 は既に終わっているといって過言ではないでしょう。しかし、Jakarta以外のオープンソースでも、よく見ると、JBossではTomcatを、HibernateはCommonsのLoggingやDBCPを、XDocletはAntを利用してます。今、Jakarta以上 に注目されているEclipseもTomcat/Ant/Luceneがインテグレートされています。Jakarta以外のほかのJavaのオープンソースも注目されはじめたとはいえ、Java のオープンソースにとって、Jakartaの重要性は今後ますます大きくなってい くといえるでしょう。

 今回の連載は、どちらかと言えば入門者向けの記事でしたが、本連載を機にJakartaのプロダクトのユーザーが1人でも増えればと思います。また、機会が あればより実践的な話をご紹介したいと思います。

 最後に、連載にご協力頂いたJa-Jakartaプロジェクトの小山、横田両氏とJakartaのプロダクトの日本への普及を促進すべくドキュメントの翻訳や日本 からのフィードバックに精進されているJa-Jakartaプロジェクトメンバーおよ び本連載の読者の皆様に感謝します。読者の皆様には、機会があれば、是非 Ja-Jakartaの活動に参加して頂ければ幸いです。中にはオープンソースプロジェ クトへの参加は難しそうと思われる方もいらっしゃるかもしれませんが、 Ja-Jakartaプロジェクトへ参加することは決して難しくありません。今後、読者とライターという関係ではなく、一緒に活動する仲間としてお会いできれば幸いです。


「現場に活かすJakarta Project」連載記事一覧