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]ボタンが押されたときの処理を追ってみる。