Employee Management3-(4)

/employee/employeeEdit.htmlは残りボタンだけかな。

<input type="button" value="confirm" m:action="#{employeeEditAction.goConfirm}"
    onclick="location.href='employeeConfirm.html'"/>
<input type="button" value="previous"
    m:action="#{employeeEditAction.goPrevious}"
    m:immediate="true"
    onclick="location.href='employeeList.html'"/>

employeeEditActionは新顔。employee.diconを見るとexamples.jsf.action.impl.EmployeeEditActionImplのインスタンスで、requestスコープというのがわかる。

<component name="employeeEditAction" class="examples.jsf.action.impl.EmployeeEditActionImpl" instance="request">
    <aspect>actionInterceptorChain</aspect>
</component>

ソースを見るとここにも見慣れたプロパティ。

public class EmployeeEditActionImpl implements EmployeeEditAction {
    private EmployeeLogic employeeLogic;
    private ProcessModeDto processModeDto;
    private EmployeeDto employeeDto;
                :
}

EmployeeLogicはテーブルEMPを操作するインタフェース。ここにはその実装クラスEmployeeLogicImplがセットされる。ProcessModeDtoはプログラムの状態を管理用。EmployeeDtoはManaged-beanのような役割を持っている。employeeEdit.htmlでは各フィールドをemployeeDtoのプロパティにValueBindingしていて、そのbindされたemployeeDtoがrequestスコープに保存される。そしてこのEmployeeEditActionImplにはsetEmployeeDto()というsetterメソッドがあるので、(requestスコープの)employeeDtoがここへセットされる。なるほど。

ボタンの方ではMethodbindingでEmployeeEditActionImplのメソッドを起動する。順番が違うけど[previous]から見てみる。

<input type="button" value="previous"
    m:action="#{employeeEditAction.goPrevious}"
    m:immediate="true"
    onclick="location.href='employeeList.html'"/>

見慣れないのがimmediate。わからない。試しに消してみる(をぉい)。するとEmployeeNoが未入力の状態で[previous]を押すとエラーメッセージ「"empno": 値を入力して下さい」が表示され前画面に戻れない。なるほど。ボタンの動作をvalidation前に実行する働きがあるんだね。その後いろいろ調べてみるとJSFのライフサイクルと密接に関係しているらしい。でも、ここではパス(汗。

で、action属性で指定されているgoPrevious()なんだけど、これは現在の状態に合わせて戻り先を決めているだけ。この戻り値はfaces-config.xmlのnavigation-ruleの定義と照合され、実際のURLが決まる。

public String goPrevious() {
    switch (processModeDto.getProcessMode()) {
        case Constants.CREATE_MODE :
            return "employeeSearch";
        case Constants.UPDATE_MODE :
            return "employeeList";
        default:
            return null;
    }
}

一方[confirm]はgoConfirm()が呼び出される。

public String goConfirm() {
    if (processModeDto.getProcessMode() == Constants.CREATE_MODE
            && employeeLogic.existEmployee(employeeDto.getEmpno())) {
        throw new EmployeeAlreadyExistRuntimeException(employeeDto
                .getEmpno().intValue());
    }
    return "employeeConfirm";
}

なんとなくわかるけど、細かく見てみる。まずexistEmployee()はEmployeeLogicのメソッドで次のようになっている。

public boolean existEmployee(Integer empno) {
	return employeeDtoDao.getEmployeeDto(empno) != null;
}

getEmployeeDto()はすでに登場済み。引数empnoをキーにテーブルEMPを検索し、該当レコードをjava.util.Listに格納して返す。この場合戻り値がnullでないということは該当レコードがある、つまりexistなのでtrueを返すわけだ。呼び出し元のif文ではこれを使って「CREATE_MODEで同じempnoを持つレコードがテーブルEMPにあれば例外EmployeeAlreadyExistRuntimeExceptionをスローする」としているわけね。ちなみにEmployeeAlreadyExistRuntimeExceptionはjava.lang.RuntimeExceptionのサブクラス(正確に間にexamples.jsf.exceptionAppRuntimeExceptionが入る)だからthrowsを書く必要がない。結果「従業員(xxxx)は既に存在します」というメッセージとして表示される。これはこのemployeeEditActionにactionInterceptorChainが適用されるからだね。多分。

反対に問題がなければ"employeeConfirm"が返され、/employee/employeeConfirm.htmlに遷移する(faces-config.xml参照)わけだが、こちらにはimmediate=trueが設定されていないからvalidationが実行される。つまりvalidationでエラーがあればこのメソッドが呼ばれることがない、ということになる。

じゃ次はemployeeConfirm.htmlだ。