18. 複数ボタン対応

同じフォームに複数のSubmitボタンがある場合の対応方法です。
通常のServletと同様にリクエストパラメータに含まれる押されたボタンの値を使いますが、Action内でチェックするよりも汎用的なやり方でやってみます。

calculate.vm

<form action="calculate.action">
  数値1:<input type="text" name="value1" value="$!value1" /><br />
  数値2:<input type="text" name="value2" value="$!value2" /><br />
  <input type="submit" value="足す" name="command" />
  <input type="submit" value="引く" name="command" />
  <input type="submit" value="かける" name="command" />
</form>
#if($resultValue)
<p>結果は$resultValue</p>
#end

押したボタンに応じて数値1と数値2を計算し、結果を表示します。

xwork.xml

<action name="calculateInit"  class="com.opensymphony.xwork.ActionSupport">
  <result name="success" type="dispatcher">
    <param name="location">/WEB-INF/vm/calculate.vm</param>
  </result>
</action>
<action name="calculate"  class="ww2.examples.event.DispatchAction">
  <param name="parameter">command</param>
  <result name="足す" type="chain">
    <param name="actionName">calculateExecute!add</param>
  </result>
  <result name="引く" type="chain">
    <param name="actionName">calculateExecute!subtract</param>
  </result>
  <result name="かける" type="chain">
    <param name="actionName">calculateExecute!multiply</param>
  </result>
</action>
<action name="calculateExecute"  class="ww2.examples.event.CalculateAction">
  <result name="success" type="dispatcher">
    <param name="location">/WEB-INF/vm/calculate.vm</param>
  </result>
</action>
calculateInit
画面の初期表示
calculate
押されたボタンに応じて実行するActionを振り分け
calculateExecute
実際に計算するAction

calculateInit(初期画面表示)→calculate(押されたボタンに応じて振り分け)→calculateExecute(計算処理)という流れになります。

DispatchAction

public class DispatchAction extends ActionSupport implements Parameterizable {
    private Map param = new HashMap();
    public String execute() {
        String parameter = (String) param.get("parameter");
        String result = ((String[]) ActionContext.getContext().getParameters()
                .get(parameter))[0];
        return result;
    }

    public Map getParams() {
        return param;
    }
    public void addParam(String key, Object value) {
        param.put(key, value);

    }
    public void setParams(Map map) {
        this.param = param;
    }
}

Actionのparam(name:parameter)の値のリクエストパラメータを取得して、その文字列をResultとして返します。
Submitボタンだけでなく、選択されたラジオボタンによって処理を変えるというのにも使うことができます。

CalculateAction

public class CalculateAction extends ActionSupport {
    private int value1;

    private int value2;

    private int resultValue;

    public String execute() throws Exception {
        throw new UnsupportedOperationException();
    }

    public String add() {
        resultValue = value1 + value2;
        return SUCCESS;
    }

    public String subtract() {
        resultValue = value1 - value2;
        return SUCCESS;
    }

    public String multiply() {
        resultValue = value1 * value2;
        return SUCCESS;
    }

    public int getResultValue() {
        return resultValue;
    }
    public void setResultValue(int resultValue) {
        this.resultValue = resultValue;
    }

    public int getValue1() {
        return value1;
    }
    public void setValue1(int value1) {
        this.value1 = value1;
    }

    public int getValue2() {
        return value2;
    }
    public void setValue2(int value2) {
        this.value2 = value2;
    }
}

実際に計算するActionです。Actionを分けるのが面倒だったのでメソッドを分けています。
アクション名!メソッド名でexecute以外のメソッドを実行させることが出来ます。
もちろんActionを分けても大丈夫です。

まとめ

DispatchActionを使えば、ボタンが増えた時の対応もxwork.xmlの書き換えと増えたボタンの処理の追加だけで済みます。
あとは他国語対応した時(ボタンの名前がlocaleによって違う)が問題ですが、その時はボタンのパラメータ名を全部変えて、パラメータのある処理に振り分けるDispatchActionを作ってみても良いかも知れませんね。