Employee Management3-(6)

では/employee/employeeConfirm.htmlのbody部分を見ていく。最初にrenderedの4連発。なるほど。employeeConfirm.htmlは全モード共通で使われる画面なんだね。

<span m:value="Create"
    m:rendered="#{processModeDto.processMode == 1}"
    m:class="display" class="notdisplay">
    Create
</span>
<span m:value="Edit"
    m:rendered="#{processModeDto.processMode == 2}">
    Edit
</span>
<span m:value="Delete"
    m:rendered="#{processModeDto.processMode == 3}"
    m:class="display" class="notdisplay">
    Delete
</span>
<span m:value="Inquire"
    m:rendered="#{processModeDto.processMode == 4}"
    m:class="display" class="notdisplay">
    Inquire
</span>

そしてhiddenの御一行様。

<input type="hidden" m:value="#{employeeDto.versionNo}"/>
<input type="hidden" m:value="#{employeeDto.empno}"/>
<input type="hidden" m:value="#{employeeDto.ename}"/>
<input type="hidden" m:value="#{employeeDto.job}"/>
<input type="hidden" m:value="#{employeeDto.mgr}"/>
<input type="hidden" m:value="#{employeeDto.hiredate}"/>
<input type="hidden" m:value="#{employeeDto.sal}"/>
<input type="hidden" m:value="#{employeeDto.comm}"/>
<input type="hidden" m:value="#{employeeDto.deptno}"/>
<input type="hidden" m:value="#{employeeDto.dname}"/>

なぜhiddenが必要かというと、このemployeeConfirm.htmlではemployeeDtoにセットされている値、つまり前の画面で入力された値を

<td class="label">EmployeeNo</td>
<td class="right"><span m:value="#{employeeDto.empno}">7788</span></td>

といった単なる文字列で表示する。これだと次の画面に(employeeDtoの内容を)渡せないのでhiddenを使ってValueBindingする。まぁ考えてみればWebアプリで当たり前にやってることだよな。

さて最後はボタンの定義。

<input type="button" value="store"
    m:action="#{employeeConfirmAction.store}"
    m:rendered="#{processModeDto.processMode != 4}"
    onclick="location.href='employeeSearch.html'"/>
<input type="button" value="previous"
    m:action="#{employeeConfirmAction.goPrevious}"
    onclick="location.href='employeeEdit.html'"/>

[store]はrenderedの条件式がprocessModeDto.processMode != 4 だから、CREATE_MODE, UPDATE_MODE, DELETE_MODEのとき表示される。DELETE_MODEで[store]は変な感じもするが、まぁいいか。

そしてaction属性ではMethodBindingを指定。employeeConfirmActionはexamples.jsf.action.impl.EmployeeConfirmActionImplのインスタンス(requestスコープ)だとemployee.diconで定義されている。

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

さてそのEmployeeConfirmActionImplだが、プロパティはいつもの常連さん(笑。

public class EmployeeConfirmActionImpl implements EmployeeConfirmAction {
	private EmployeeLogic employeeLogic;
	private ProcessModeDto processModeDto;
	private EmployeeDto employeeDto;
				:
}

EmployeeLogicはインタフェースで実際はEmployeeLogicImplというテーブルEMPに対する操作を実装したクラスインスタンスがセットされる。ProcessModeDtoはプログラムの状態を管理用。EmployeeDtoはmanaged-bean的に使われるもので、前画面から渡されたデータが入っている。

では[store]が押されたとき呼び出されるEmployeeLogic#store()を見てみる。

public String store() {
    switch (processModeDto.getProcessMode()) {
        case Constants.CREATE_MODE :
            employeeLogic.insert(employeeDto);
            break;
        case Constants.UPDATE_MODE :
            employeeLogic.update(employeeDto);
            break;
        case Constants.DELETE_MODE :
            employeeLogic.delete(employeeDto);
            break;
    }
    return "employeeSearch";
}

ふむふむ。現在の処理モードに合わせてメソッドを呼び分けているんだね。EmployeeLogicImpl側のメソッド定義は次のようになっている。

public void insert(EmployeeDto dto) {
    employeeDtoDao.insert(dto);
}

public void update(EmployeeDto dto) {
    employeeDtoDao.update(dto);
}

public void delete(EmployeeDto dto) {
    employeeDtoDao.delete(dto);
}

やはりEmployeeDtoDao経由でS2Daoに任せている。

public void insert(EmployeeDto dto);
public void update(EmployeeDto dto);
public void delete(EmployeeDto dto);

これだけでS2Daoは更新系SQLを自動的に生成して実行してくれる。どうしてそんなことができるかというと、この引数で渡しているEmployeeDtoにはTABLEアノテーション(正確に言えばスーパークラスEmployeeから継承したもの)があるから対象テーブルがわかる。あとは多分Metaデータを取得したり、リフレクションなどを使ってSQL文を生成しているんでしょう。また

  • EMPにはVERSIONOというカラムがある AND
  • EmployeeDtoには同名のプロパティがある(Employeeから継承したもの)

ので、これを使って自動的に排他制御(いわゆる「楽観的なロック」)が行われる。これで失敗すると例外UpdateFailureRuntimeExceptionがスローされるらしいが、その辺はまだチェックしていない。ともかく更新に成功すれば"employeeSearch"が返されるので、次に表示するのは/employee/employeeSearch.htmlになる(faces-config.xmlで定義されている)。

一方[previous]で呼び出されるgoPrevious()はもっと簡単。単に次の表示ページを決めるための文字列を返しているだけ。

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

あー、長かった。これでemployeeSearch.htmlの[create]ボタンを押されて始まる一連の処理はひとまず終わりかな。次は同じくemployeeSearch.htmlにある[search]ボタンが押されたときの処理を追ってみる。