Strutsメモ

メッセージ・リソースの参照
Action.execute()内でメッセージ・リソースを取得するには、次のようにします。

MessageResources resources = getResources(request);
String workDir = resources.getMessage("work.file.dir");
String errorMessage = resources.getMessage("errors.notfound", "ファイル");
String directMessage = resources.getMessage("エラーですよ", false);

2番目の例は、メッセージ・リソースが{0}というプレースホルダを持つ場合に、 2番目の引数の値でそれを置き換えることを示します。 プレースホルダは{0}から{3}までの4つがあり、それぞれに応じた MessageResources.getMessage()メソッドがあります。
3番目の例は、Struts 1.3で新しくサポートされたシグネチャで、 最初の引数にメッセージのキーではなく、メッセージそのものを指定するものです。 ただしこれを使いまくるとメッセージ・リソースの利点が失われるので、使いどころは難しいです。

ApplicationResources中のバックスラッシュ
ApplicationResources中の\は\\と書きます。

リクエスト・パラメータのエンコーディングを設定する
フォームの入力に日本語を想定する場合や、LookupDispatchActionで Submitボタンのラベルに日本語を使う場合には、 パラメータを日本語のエンコーディング(Windows-31Jなど)に変換する処理が必要になります。 よく使われるのは、

  1. サーブレットフィルタを使う
  2. RequestProcessorを自分で拡張
  3. ActionServletを自分で拡張
のいずれかだと思います。 サーブレットフィルタはServletの機能であってStruts固有の解決策ではないので、 ここでは省略します。 そのようなフィルタで出来合いのものはないのか?ということですと、一例を挙げると
  • Strutsより新しいフレームワーク、Spring FrameworkにはCharacterEncodingFilterが入っている
  • tomcat-examples.jarにはfilters.SetCharacterEncodingFilterが入っているらしい(説)
また、上記以外に自分でActionの処理の中でエンコーディングを変換することもできますが、 常にこれをやるのは保守がしづらくなるのであまりお勧めできません。

DynaActionForm fb = (DynaActionForm) form;
String memo = request.getParameter("memo");
if(memo != null){
    memo = new String(memo.getBytes("8859_1"), "Shift_JIS");
}
fb.set("memo", memo);

RequestProcessorを自分で拡張するサンプルです。

package shiten.struts.common;
import org.apache.struts.action.RequestProcessor;
import javax.servlet.http.*;
public class EncodingProcessor extends RequestProcessor {
    public boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {
        try {
            request.setCharacterEncoding("Shift_JIS");
        } catch (Exception ex) { ex.printStackTrace(); }
        return true;
    }
}

そして、struts-config.xmlに次のように書き加えます。

<controller processorClass="shiten.struts.common.EncodingProcessor" />

次に、ActionServletの拡張クラスを作る方法です。 例えば次のように、doPost()メソッドの中で、エンコーディングを Windows-31Jに変更する処理を追加したクラスを作ります。

package example.strutsutils;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionServlet;

/**
 * POST時に、リクエスト及びレスポンスのエンコーディングを自動的にWindows-31J
 * に変換する処理を行う、ActionServletの派生クラスです。
 */
public class CustActionServlet extends ActionServlet {
    public CustActionServlet() {
        super();
        log.info("CustActionServlet start.");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        super.doGet(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        request.setCharacterEncoding("Windows-31J");
        response.setContentType("text/plain; charset= Windows-31J");
        super.doPost(request, response);
    }
}

そして、WEB-INF/web.xmlの、Servletのクラス定義を、

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    ...

から

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>example.strutsutils.CustActionServlet</servlet-class>
    ...

のように書き換えます。

Strutsタグの属性値にJSPスクリプトレットを使いたい
これは私が結構はまって悩んだのですが、例えば nested:iterateタグでフォーム要素を繰り返し埋め込むとき、それらのイベントハンドラとして、 onclickやonchangeの属性値の中でJavaScript関数の引数を動的に指定する場合に、

<nested:checkbox property="July" value="1" onclick="checked(<%= index %>)" />

としても、<%= index %>が直接出てしまいうまくいかない、ということです。 これは正解は

<nested:checkbox property="July" value="1" onclick='<%= "checked(" + index + ")" %>' />

で、これならindexの部分がnested:iterateの繰り返し変数(indexId)の現在の値に置き換わります。 なんとも不思議な仕様ですね。

アプリケーション・ログにstruts-config.xmlの解析エラーが出る
例えば、こんなのです。

致命的: Parse Error at line 126 column 17: The content of element type "struts-config"
 must match "(data-sources?,form-beans?,global-exceptions?,global-forwards?,
 action-mappings?,controller?,message-resources*,plug-in*)".
org.xml.sax.SAXParseException: The content of element type "struts-config" must match
 "(data-sources?,form-beans?,global-exceptions?,global-forwards?,action-mappings?,
 controller?,message-resources*,plug-in*)".

この原因を調べて対応するには、次のようにします。
  1. まず簡便な方法として、struts-config.xmlをエクスプローラでつまんで MSIEなどのWebブラウザにドラッグ&ドロップします。 XML文書としての文法エラーがあればこれで表示されるので分かります。
  2. そうでない場合は、XMLの文書型定義(DTD)に違反している可能性があります。 DTDでは、タグが出てくる順序も規定されています。 struts-config.xmlを上から順番に見て、上のメッセージに出てくる順番通りになっているか確認します。
  3. その次に、1つしか書けないタグを2つ以上書いていないかも確認します。 1つしか書けないというのは、上のメッセージで後ろに?がついているもの (全く書かないか、書いても1つだけの意)です。 後ろに*がついているものは複数回書けます。 例えば「controller」というタグは1回しか書けないので、2つ以上書いているとアウトになります。

Actionに外部からパラメータを渡す
ServletContextやサーブレットにweb.xmlからパラメータを渡すことができるように、 Actionにもパラメータを渡すことができます。 これにより、動作環境などに関する情報が変わっても、 プログラムを書き換えて再コンパイルしなくても、環境設定情報を変更することができます。
Struts 1.2以前でパラメータを渡すには、struts-config.xmlのactionタグのparameter属性を使います。

<action path="/ATPP321"
  name="ATPP321Form" attribute="ATPP321Form"
  parameter="P0Q0R0S0"
  input="/ATPP321.jsp" scope="session" validate="false"
  type="atpcl01.struts.action.ATPP321Action">
  <forward name="success" path="/ATPP321.jsp" />
</action>

Actionクラスからパラメータを取り出すには、ActionMapping#getParameter()を使います。

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

    String param = mapping.getParameter();

    // ...
}

Struts 1.3からは上記に加え、「Arbitrary configuration properties」 と呼ばれる新しい機能が追加されました。上記のparameter以外に、set-property要素が使えるようになり、

<action path="/ATPP321" ... />
  <set-property key="foo" value="bar"/>
</action>

と書くと、Actionクラスの中から

String foo = mapping.getProperty("foo");

で値(ここでは"bar")を取り出すことができます。

複数のボタンがあるフォームを作る
これをやるには、別のページで触れている、LookupDispatchActionクラスを使う方法がありますが、 それよりも簡単で分かりやすいのは、JavaScriptで強引にリンク先を変えてしまう方法です。 以下のようにJavaScriptの関数を定義します。

function f_submit(action){
    objForm = document.forms[0];
    objForm.action = action + ".do";
    objForm.method = "post";
    objForm.submit();
}

フォームでは、Submitボタンではなく、type="button"のボタンを複数個作り、 次のようにonClick=で先ほどの関数をコールします。

<html:form action="/Shori1">
...
<input type="button" value="登録" onClick="f_submit('Shori1')">
<input type="button" value="削除" onClick="f_submit('Shori2')">
</html:form>

これで、「登録」ボタンが押されたらShori1.doが、 「削除」ボタンが押されたらShori2.doが実行されます。

struts-config.xmlを複数に分ける
web.xmlで、初期化パラメータconfigに、 構成ファイルのパスをカンマで区切って以下のように書けばOKです。

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
  <init-param>
    <param-name>config</param-name>
    <param-value>
      /WEB-INF/struts-config.xml,/WEB-INF/struts-config-common.xml
    </param-value>
  </init-param>
</servlet>

注意点として、「controller」「message-resources」「plug-in」の各要素は、 2個所以上に別々の内容を記述することはできません。 2個所以上に書くと、設定が一切効かなくなってしまいます。 但し、全く同じ内容を2個所以上に書くのはOKみたいです。 普通は、どれか代表の構成ファイルを決めて、これらはそのファイルだけに書くようにします。

Server Side Java Index Top

(first uploaded 2003/11/20 last updated 2007/01/06, URANO398)

楽天モバイル[UNLIMITが今なら1円] ECナビでポインと Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!


無料ホームページ 無料のクレジットカード 海外格安航空券 解約手数料0円【あしたでんき】 海外旅行保険が無料! 海外ホテル