肥満診断 - その2

フォームに身長と体重を入力し、Submitボタンを押したら、別のページで診断結果を表示するように、肥満診断を修正する。
HTMLで作成するビューは、前の肥満診断を入力フォームを表示する部分と結果を表示する部分にわけることになる。それぞれの内容は以下の通り。
入力フォーム部分(bmi_form.htm):

<h1>BMIによる肥満度診断</h1>
$inputForm

結果表示部分(bmi_result.htm):

<h1>BMIによる肥満度診断 - 結果</h1>
#if ($diagnosis == "過体重" || $diagnosis == "肥満")
<h2 class="diagnosis">$diagnosis</h2>
#end
あなたの身長は
<span class="cmHeight">$cmHeight</span>
cmです。<br/>
あなたの体重は
<span class="kgWeight">$kgWeight</span>
kgです。<br/>
<hr/>
あなたのBMIは
<span class="bmi">$bmi</span>
です。<br/>
あなたは「
<span class="diagnosis">$diagnosis</span>
」です。<br/>
ちなみにあなたの標準体重は
<span class="idealWeight">$idealWeight</span>
kgです。<br/>

フォームを定義するBmiFormPageクラスは、Submitボタンが押されたら、結果を表示するbmi_result.htmを表示するように修正する必要がある。その際、BMIの計算結果を保持するオブジェクトを受け渡す。
BMIの計算結果の受け渡しは、PageクラスのgetContext()メソッドで得られるContextクラスのオブジェクトを介して行う。オブジェクトを渡す側では、適当な名前をつけて、ContextクラスのsetSessionAttribute()メソッドを呼ぶ。オブジェクトを受ける側では、その名前をキーにして、ContextクラスのgetSessionAttribute()メソッドを呼ぶ。ここでは、受け渡しするオブジェクトはBmiクラスのオブジェクトで行う。
BmiFormPageクラスの内容は以下の通り:

package com.fujitsu.fst.hal;

import net.sf.click.control.FieldSet;
import net.sf.click.control.Form;
import net.sf.click.control.Submit;
import net.sf.click.control.TextField;
import net.sf.click.util.ClickLogger;

public class BmiFormPage extends BorderPage {
    public String title = "BMIによる肥満度診断";
    public Form inputForm = new Form();
    public double bmi;
    public String diagnosis;
    public double idealWeight;
    
    /* cmHeightField, kgWeightFieldは、DoubleFieldにしたいところ
     * だが、DoubleFieldは、required statusが利かないようだ。
     * フィールドをクリアしてsubmitボタンを押してもエラーにならない。
     * なので、TextFieldにしておく。
     */
    private TextField cmHeightField;
    private TextField kgWeightField;
    private Submit submitButton;
    private double cmHeight = 170.0;
    private double kgWeight = 50.0;
    
    private ClickLogger logger = ClickLogger.getInstance();
    
    public BmiFormPage() {
        logger.debug("Bmiform#<init>(): this = " + this);
        FieldSet inputFieldSet = new FieldSet("bmi", "");
        inputForm.add(inputFieldSet);
        cmHeightField = new TextField("cmHeight", "身長 (cm)", true);
        inputFieldSet.add(cmHeightField);
        kgWeightField = new TextField("kgWeight", "体重 (kg)", true);
        inputFieldSet.add(kgWeightField);
        
        submitButton = new Submit("submit", "submit", this, "onStartDiag");
        inputForm.add(submitButton);
        
        Bmi bmi = new Bmi(cmHeight, kgWeight);
        this.bmi = bmi.getBmi();
        this.diagnosis = bmi.getDiagnosis();
        this.idealWeight = bmi.getIdealWeight();
    }
    
    /* (一応動くが、こんなのでよいのかわからない!)
     * submitボタンを押すと、一見そうは見えないが、画面が遷移している。
     * (thisポインタの値がsubmitボタンを押す前と押したあとで違う。)
     * inputFormは、新しい画面のオブジェクトになっているが、フォームの中の
     * 部品が保持する値などは、オブジェクトに設定してないので、フォームから
     * 値を取り直す必要がある。
     */
    public boolean onStartDiag() {
        logger.debug("Bmiform#onStartDiag(): this = " + this);
        FieldSet inputFieldSet = (FieldSet)inputForm.getField("bmi");
        this.cmHeightField = (TextField)inputFieldSet.getField("cmHeight");
        this.kgWeightField = (TextField)inputFieldSet.getField("kgWeight");
        logger.debug("cmHeightField = " + cmHeightField);
        logger.debug("kgWeightField = " + kgWeightField);
        if (cmHeightField == null || kgWeightField == null) {
            return false;
        }
        try {
            this.cmHeight = Double.parseDouble(cmHeightField.getValue());
            this.kgWeight = Double.parseDouble(kgWeightField.getValue());
        } catch (NumberFormatException e) {
            return false;
        }
        Bmi bmi = new Bmi(cmHeight, kgWeight);
        this.bmi = bmi.getBmi();
        this.diagnosis = bmi.getDiagnosis();
        this.idealWeight = bmi.getIdealWeight();
        this.getContext().setSessionAttribute("bmi", bmi);
        this.setRedirect("bmi_result.htm");
        return true;
    }
    
    public void onInit() {
        cmHeightField.setValue(Double.toString(cmHeight));
        kgWeightField.setValue(Double.toString(kgWeight));
    }
}

Bmiオブジェクトを受け取るBmiResultPageクラスは以下の通り:

package com.fujitsu.fst.hal;

public class BmiResultPage extends BorderPage {
    public double bmi;
    public String diagnosis;
    public double idealWeight;
    public double cmHeight;
    public double kgWeight;
    
    public void onInit() {
        if (getContext().hasSessionAttribute("bmi")) {
            Bmi bmi = (Bmi)getContext().getSessionAttribute("bmi");
            this.cmHeight = bmi.getCmHeight();
            this.kgWeight = bmi.getKgWeight();
            this.bmi = bmi.getBmi();
            this.diagnosis = bmi.getDiagnosis();
            this.idealWeight = bmi.getIdealWeight();
        }
    }
}

データの受信は、結果を表示するページができて、それを表示する前に行うので、onInit()メソッドで行っている。データを受ける前に、目的のデータがあるかどうかをhasSessionAttribute()メソッドでチェックしている。