Struts構成ファイルの書き方メモ

struts-config.xmlとvalidation.xmlの書き方のメモです。
このページのサンプルはStruts 1.2用のものです。 1.3用へ移行する際の変更点は バージョン1.2から1.3への移行のページに載せました。


struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
          "http://struts.apache.org/dtds/struts-config_1_2.dtd">

<struts-config>

  <!-- ========== Data Source Configuration =============================== -->

  <!-- ========== Form Bean Definitions =================================== -->
  <form-beans>
    <form-bean name="ShitenEditForm" dynamic="true"
               type="org.apache.struts.validator.DynaValidatorForm">
      <form-property name="shitenCode" type="java.lang.String" initial="00100" />
    </form-bean>
    <form-bean name="ShitenInputForm" type="shiten.struts.ShitenInputForm"/>
  </form-beans>

  <!-- ========== Global Forward Definitions ============================== -->
  <global-forwards>
    <forward   name="logoff"               path="/logoff.do"/>
    <forward   name="logon"                path="/logon.jsp"/>
    <forward   name="success"              path="/mainMenu.jsp"/>
  </global-forwards>

  <!-- ========== Action Mapping Definitions ============================== -->
  <action-mappings>

    <action path="/ShitenEditC1" type="shiten.struts.ShitenEditC1Action"
            attribute="ShitenEditForm" name="ShitenEditForm"
            scope="request" validate="false" input="/ShitenEditC1.jsp">
      <forward name="success" path="/ShitenEditC2.jsp"/>
    </action>

    <action path="/ShitenEditC2" type="shiten.struts.ShitenEditC2Action"
            attribute="ShitenInputForm" name="ShitenInputForm"
            scope="session" input="/ShitenEditC2.jsp">
      <forward name="success" path="/ShitenEditC3.jsp"/>
    </action>

  </action-mappings>


  <!-- ========== Controller Configuration ================================ -->
  <controller/>

  <!-- ========== Message Resources Definitions =========================== -->

  <message-resources parameter="shiten.struts.ApplicationResources"/>

  <message-resources
    parameter="org.apache.struts.webapp.example.AlternateApplicationResources"
    key="alternate">
  </message-resources>


  <!-- ========== Plug Ins Configuration ================================== -->

  <plug-in className="org.apache.struts.plugins.ModuleConfigVerifier"/>

  <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames"
     value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
  </plug-in>

</struts-config>

Form Bean Definitions
form-beanタグにはFormBeanのnameとtypeを通常指定します。
FormBeanの定義は、Dyna****Formを使う方法と、 自分でActionForm,ValidatorFormを継承したJavaクラスを作って使う方法の2種類に大きく分けられます。
DynaActionForm、DynaValidatorFormを使用する際には dynamic="true"とし、typeにそれらのクラスの名前を書きます。 form-propertyタグで個々の入力項目(プロパティ)を設定します。 initial=で入力内容の初期値を設定することができます。
一方 Dyna***Formではなく、JavaクラスでFormBeanを定義する場合は、 form-propertyは全て省略できます。(書いてもOKですが、特に益がないと思います)

Action Mapping Definitions
actionタグにはActionクラスのpathとtypeを指定します。 attribute=とname=は、通常nameだけを指定すればOKです。 nameはForm Beanの名前で、form-beanに書いてある名前のどれかと一致する必要があります。 この名前がHTMLフォームの名前になります。 (JSPでJavaScript等を使って内容をいじる場合は、「document.フォーム名」で参照します)
attribute=を省略すると、name=で指定した名前が、 sessionなどのスコープ中に保持されるそのオブジェクトの属性名にもなりますが、 これを変えたい場合には、attribute=で指定します。 これは、同じFormBeanクラスを、別々の画面で使う場合に、 それらが衝突しないようにするためなどに使います。
FormBeanがValidatorFormを継承してvalidate()で妥当性検証を行う場合や、 DynaValidatorFormを使って妥当性検証を行うとき、 validate="true"と書くか、または省略します。(デフォルトはtrue) Strutsが用意する妥当性検証が不要な場合に限り、falseと指定します。
inputはvalidate="true"の場合のみ必須で、 妥当性検証が失敗したときに、戻されるページのパスを指定します。
なお、Struts 1.2以降では、 Struts User Guideのサンプル のように、マッピング名にワイルドカードを使い、 「マッピング名-Actionクラス名-フォワード先のJSP(or Action)」 の組み合わせのうち命名のパターンが同一のものをまとめて定義できるようになりました。 これを使うと、1つのアプリケーション内に画面が増えてくると段々構成ファイルがずらずらと長くなって可読性が悪くなる、 という保守上の問題点をかなり解決できます。
なお、ワイルドカードはActionマッピングの定義にしか使えません。 Form Bean Definitionにはワイルドカードは使えないので、 新しい画面を作ると、Actionマッピングはワイルドカードでカバーできたとしても、 少なくともForm Beanの定義だけは構成ファイルに書き足す手間は必要です。 これは残念無念。

Message Resources Definitions
メッセージ・リソースファイルを指定します。 サンプルアプリケーションにはサンプル用のリソースファイルのパスが書かれているので、 普通アプリケーションごとに書き換えることになるでしょう。 これはCLASSPATH上に配置し、ディレクトリ階層をパッケージ階層のノリで記述します。 例えば、WEB-INF/classes/shiten/strutsに ApplicationResources.propertiesという名前でリソースファイルを置いた場合の記述が上記の例です。 「.properties」は書く必要はありません。 なおリソースに日本語を使う場合にはnative2asciiしておくのを忘れずに。

Plug Ins Configuration
Strutsに対するプラグインをここに書きます。validation.xmlによる妥当性検証を行う場合には、 サンプルのようにValidatorPlugInを書きます(サンプルアプリケーションに書かれているままです)。


validation.xml

<?xml version="1.0" encoding="Shift_JIS" ?>

<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
          "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">

<form-validation>

  <formset>
    <form name="ShitenEditC1Form">
      <field property="shitenCode" depends="required">
        <arg position="0" key="shitenCode.displayName" />
      </field>
    </form>
  </formset>

</form-validation>

formsetタグの中
formタグで、妥当性検証を行うフォームの名前を指定します。 この名前を、struts-config.xmlのaction-mappingsで指定される各Actionのフォームの名前(*1) と一致させると、そのフォームのSubmit時にこの妥当性検証が有効になります。
fieldタグで、チェックする入力項目(プロパティ)を指定します。 dependsはバリデータの名称で、requiredは必須チェック(空白の場合エラー)のことで、 他にも何種類かStrutsで用意されているバリデータがあります。 その一覧は例えば TECHSCOREのこのページ などで紹介されています。
このrequiredチェックに引っかかったら、 メッセージリソースerrors.required の値がエラーメッセージとして(html:errorsタグの位置に)表示されます。 「error.」ではなく「errors.」なので注意して下さいね。 この、どのバリデータが標準でどのメッセージリソースを参照してエラーメッセージを作るか、 というのは、validator-rules.xmlに書かれています。
arg position="0"〜"3"には、errors.requiredの中に{0}〜{3}が書かれていた場合、 その位置に置き換わる文字列を格納しているメッセージリソースの名前 を指定します。 (置き換わる文字列そのものではないので注意。 置き換わる文字列そのものをここに書きたい場合は、resource="false"と書けばそれも可能です)
上記の例ではarg position="0" のkeyをshitenCode.displayNameとしているので、 メッセージリソースshitenCode.displayNameの内容が、 errors.requiredの中の{0}の位置に置き換わります。 例えば、errors.requiredが「{0}が入力されていません。」 で、shitenCode.displayNameが「支店コード」だった場合、 エラーメッセージは「支店コードが入力されていません。」となります。
なお、このarg position="0"〜"3"は比較的新しい書き方で、昔はarg0 〜 arg3という書き方でした。 Strutsに同梱されるJakarta Commons Validatorが1.1.xから1.3.xに上がった際に、 後者の書き方はできなくなったので注意が必要です。
ちなみに、上記*1でstruts-config.xmlでのフォームの名前ですが、

<action path="/updateRecord" attribute="MMBeanForm" name="ShitenForm"
    input="/edit.jsp" type="mm.action.UpdateAction">
    <forward name="success" path="/result.jsp" />
</action>

このようにname属性とattribute属性の値が異なる場合、どちらの名前が validation.xmlのフォーム名との照合に使われるのでしょうか? 答は「attribute属性の値が使われる」です。 でもちょっとヘンな気がしますね。name属性の方が「論理的」な名前なんですから、 こちらが渡されたほうが分かりやすいし、Form Beanを共通化・抽象化する際にも便利です。 が、一応この動作は意図されたもののようです。 これを切り替えるために、Struts 1.2.4からValidatorForm#getValidationKey()というメソッドが用意されました。 下のようにオーバーライドすることで、name属性を渡すことができるようになります。

public String getValidationKey(ActionMapping mapping, HttpServletRequest request) {
    return mapping.getName();
}

maxlengthバリデータとintRangeバリデータ

<field property="mojimade" depends="maxlength">
  <arg position="0" key="mojimade.displayName" />
  <arg position="1" name="maxlength" key="${var:maxlength}" resource="false"/>
  <var>
    <var-name>maxlength</var-name><var-value>5</var-value>
  </var>
</field>

<field property="intran" depends="integer,intRange">
  <arg position="0" key="intran.displayName"/>
  <arg position="1" name="intRange" key="${var:min}" resource="false"/>
  <arg position="2" name="intRange" key="${var:max}" resource="false"/>
  <var><var-name>min</var-name><var-value>1</var-value></var>
  <var><var-name>max</var-name><var-value>100</var-value></var>
</field>

requiredバリデータはホントに簡単でしたが、 変数を使うため若干複雑なバリデータの2つがmaxlengthとintRangeです。 maxlengthは入力文字列の最大の「文字数」を、intRangeは整数の最小値と最大値を制限するバリデータです。 「文字数」を括弧で囲んだのは鋭い皆さんはご想像の通り、 「文字数」は「バイト数」ではありません。 つまり、入力フォームのFORMタグのmaxlength=と全く変わりませんので、ほとんど役に立ちません。
なんでそんなモノがあるのかというと、Strutsバリデータの元になっている Jakarta Commons Validatorは別にWebフォームの入力チェック専用というわけでなくて、 もっと汎用的なライブラリなためですが…
それはそれとして、ではバイト数で制限するにはどうすればいいかというと、標準のStrutsでは不可能です。 ので、一般の開発チームでは日本中でそれをやるカスタム・バリデータを作っているはずです。 無論、私も作りました。 とりあえず、カスタムバリデータの作り方はこちらです。

それで、今度はarg position="0"だけでなくarg position="1" というものが出てきています。 name=の値はそのリソースを適用するバリデータを指定します。 というか、このプロパティではmaxlengthしかバリデータがないのでこれになります。 key="${var:maxlength}"というのはその下に出てくる変数「maxlength」の値を参照するという意味、 resource="false"というのはkeyの値を持つメッセージリソースを探すのではなく、 keyの値そのものを出力してくれという指令です。 そして、変数maxlengthに5と指定しているので、 5文字(くどいですが5バイトではない…)以上入力するとエラーになります。
で、エラーになったときですが、 今度は「errors.maxlength」というメッセージリソースの値が使われます。 従って、errors.maxlengthリソースの値が「{0}は{1}文字以下でなければいけません。」、 mojimade.displayNameリソースの値が「営業コード」だったとすると、 表示されるメッセージは「営業コードは5文字以下でなければいけません。」となります。

intRangeの要領も同じです。上記の例では、2つのバリデータをカンマで区切ってdependsに指定しています。 integerやintRangeは値が空欄(空文字列)の場合はエラーにならないので、 必須チェックもしたい場合には "required,integer,intRange" とする必要があります。 このように1つのプロパティにバリデータが複数の場合、 {1}以降のプレースホルダーは、各バリデータごとに異なることになります。 上記の例では、arg position="1"、arg position="2"は name="intRange" となっているので、 integerバリデータに引っかかったときにはこれらの値は使われません。

ちなみに、上記のmaxlength、min、maxなどの変数名は、 各バリデータによって固定で決まっているので、勝手に自分の好きな名前に変えることはできません。 他の名前の変数は設定しても無意味です。 エラーにならないのでかえって分かりにくい落とし穴。私はこれにはまって延々悩みました。
またintegerバリデータのさらに重大な注意ですが、 Strutsバリデータとゆーものは、Form Beanに値を設定してからチェックをします。 従って、 Form Beanのプロパティのデータ型が既にintやIntegerの場合、 バリデータを指定する意味がないので、 Form Beanのプロパティは一般にjava.lang.String にしておくのがいいでしょう。

Server Side Java Index Top

(first uploaded 2003/10/26 last updated 2007/02/28, URANO398)

テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル