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だ。