JavaEE 7をやってみよう。 JSF 画面遷移 その2
その1のつづき。
登録画面用のManaged Beanを作る。
その前に、Managed Beanで使う艦種情報検索用の機能をJPAの回で作ったEJBに追加する。
WarshipServiceLocal.java
EJBモジュールのインターフェイス。
ここにgetAllTypeList()とgetWarship(Warship key)を追加する。
getAllTypeList()は艦種リストを取得するメソッド。
主に艦種選択リストのデータ取得に使用する。
getWarship(Warship key)は艦艇IDから艦艇情報を取得するメソッド。
これはまだ使う予定は無いが、更新を作るときに使うのでついでに作る。
package ejbModule; import java.util.List; import javax.ejb.Local; import model.Warship; import model.WarshipType; @Local public interface WarshipServiceLocal { public List<Warship> getAllList(); public List<WarshipType> getAllTypeList(); public Warship getWarship(Warship key); }
WarshipService.java
getAllTypeList()とgetWarship(Warship key)の実装を追加する。
getAllTypeList()に関しては、getAllListメソッドと同じ作りなので楽勝。
条件を付ける方にしても、プライマリキーで検索する場合では、
すでにEntityManaegerに用意されているfindメソッドを使えば良いのでこれまた楽勝。
findメソッドの第1パラメータが取得するクラス、第2パラメータがキー値。
この場合、取得クラスはWarshipクラスで、キー値はStringのID。
もっとも、対象テーブルが複合キーだったりすると、
このやり方は通用しないのだが(なんせ、第2パラメータに渡せるのはキー値そのものだから)、
そのことについてはまた、別の機会に。
package ejbModule; import java.util.List; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import model.Warship; import model.WarshipType; /** * Session Bean implementation class WarshipService */ @Stateless @LocalBean @TransactionAttribute(TransactionAttributeType.REQUIRED) public class WarshipService implements WarshipServiceLocal { @PersistenceContext private EntityManager entityManager; /** * Default constructor. */ public WarshipService() { } @Override public List<Warship> getAllList() { return entityManager.createNamedQuery("Warship.findAll", Warship.class).getResultList(); } @Override public List<WarshipType> getAllTypeList() { return entityManager.createNamedQuery("WarshipType.findAll", WarshipType.class).getResultList(); } @Override public Warship getWarship(Warship key) { return entityManager.find(Warship.class, key.getId()); } }
EJBを直したら、次はManaged Bean。
WarshipDefault.java
艦種、艦名保持用のフィールド、
艦種リスト取得、
艦艇取得を共通化するためのabstractクラス。
編集画面でも同じような構成の画面になるので、こんなクラスを作成してみた。
新規登録画面でのManaged Beanはこれを継承したものとなる。
package app.manage; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.faces.model.ListDataModel; import model.Warship; import model.WarshipType; import ejbModule.WarshipServiceLocal; public abstract class WarshipDefault { @EJB protected WarshipServiceLocal ejb; /** 入力フィールド値の格納用 **/ private Warship warship; @PostConstruct private void init() { warship = new Warship(); warship.setWarshipType(new WarshipType()); } public ListDataModel<WarshipType> findAllWarshipType() { return new ListDataModel<WarshipType>(ejb.getAllTypeList()); } public void find() { Warship key = new Warship(); key.setId(getWarshipId()); warship = ejb.getWarship(key); } public Warship getWarship() { return warship; } public void setWarship(Warship warship) { this.warship = warship; } public abstract Integer getWarshipId(); public abstract void update(); }
WarshipRegister.java
今のところ登録処理は作ってないので、
実質、空実装に等しいが、登録メソッドも作った。
package app.manage; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @RequestScoped @Named(value="WarshipReg") public class WarshipRegister extends WarshipDefault { @Override public Integer getWarshipId() { // 新規登録ではfindを使わないため、空実装 return null; } @Override public void update() { // TODO ejbに登録メソッドを作成後に実装 } }
ここまでで、ひとまず、Java側はおしまい。
新規登録画面のinsert.xhtmlに艦種リストの呼び出しと登録メソッドの呼び出しを追加する。
insert.xhtml
入力項目の格納先には、Managed Beanに用意したフィールドをあてがう*1。
フィールドはWarshipクラスなので、Warshipクラスのメンバをそれぞれ指定することになる。
艦種選択リストのOptionタグに当たる部分については、selectItemsタグを使ってListDataModelから生成できる。
selectItemsタグはselectOneMenuタグの中に記述する。
使い方はdataTableタグと似ている。
valueにはリスト値を、varにはその要素を表す変数名を指定できる点は、全く同じ。
他に、itemLabelには表示する値、itemValueには選択時に送信される値を設定する。
itemLabelEscpedは文字通り表示値をエスケープするか否かで、trueにすれば、
HTMLコードもそのまんま文字として出力できる。
あとは、登録時の呼び出しとして、
登録ボタンにactionListenerを追加した。
actionListenerには、登録メソッドたる、updateメソッドの呼び出しを記述した。
actionListenerはManaged Beanのメソッドの呼び出しが行える。
ただし、呼び出すメソッドにはパラメータを持たせることが出来ない。
戻り値はvoidかStringであることが条件。
JSFでは、actionLisener → actionの順で処理が行われるので、
actionListenerを使えば、メソッド呼び出し後に画面遷移を行うことができる。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h2><h:outputLabel value="#{staticText['warship.reg.lblSreenTitle']}" /></h2> <hr/> <h:messages id="errorText" layout="table" errorClass="error-message"/> <h:outputLabel value="#{staticText['warship.reg.lblWarshipType']}" /> <h:selectOneMenu id="warshipType" value="#{WarshipReg.warship.warshipType.typeId}" styleClass="warship-type-select" > <f:selectItems value="#{WarshipReg.findAllWarshipType()}" var="warshipType" itemLabel="#{warshipType.name}" itemValue="#{warshipType.typeId}" itemLabelEscaped="true" /> </h:selectOneMenu> <h:outputLabel value="#{staticText['warship.reg.lblWarshipName']}" /> <h:inputText id="warshipName" value="#{WarshipReg.warship.name}" styleClass="warship-name-input" required="true" autocomplete="off" /> <br/> <h:commandButton value="#{staticText['warship.reg.btnRegister']}" action="catalog" actionListener="#{WarshipReg.update()}" /> <h:commandButton value="#{staticText['warship.reg.btnRegisterAndRegister']}" /> </ui:composition>
といったところで、テスト実行。
画面を動かしてメニューから新規登録を選ぶと入力画面へ遷移でき、
入力画面では艦種選択リストが表示できている。
また、艦名を入力した後に登録ボタンを押すと一覧画面に遷移できる。
こんな感じで選択リストの表示と、登録ボタンの処理はできた。
次回はJPAの続きとして新規登録(Insert)の実装を行う。
*1:ほんとは、入力項目と1対1とフィールドを設けたほうがわかりやすいとは思うけど、色々思ってこうした