JPA + EJB + JSF による Web アプリケーション(その 3)
さて、DAO の実装が済んだところで Web アプリケーション側の構築に入ります。普通に Servlet と JSP でも作れますが、今回は JSF を使ってみましょう。
JSF(JavaServer Faces) とは
JSF は Java EE 純正規格であるコンポーネントフレームワークです。Struts との決定的な違いは「Java EE 純正の API である」ということでしょう。*1
Struts では View にカスタムタグが使えましたが、あくまでも JSP です。それに対し、JSF 2.0 からは Facelets という、独自のタグが用意された XHTML で View を作成します。また、Struts では ActionForm を継承した Form Bean のクラスと Action クラスを継承したクラスを用意する必要がありましたが、JSF では管理(Managed) Bean を使います。これは他のクラスを継承しない POJO(Plain Old Java Object)として作成できます。*2さらに JSF 2.0 になって、管理 Bean はアノテーションで指定するだけで、設定ファイル(faces-config.xml)を作成・編集する必要がなくなりました。Struts では struts-config.xml の作成・編集が不可避だったので、これは大きな違いです。
管理 Bean を作成する
ではさっそく管理 Bean を作成してみましょう。Eclipse で JSF プロジェクトを作成してください。
package jp.mydns.akanekodou; import javax.faces.bean.ManagedBean; import javax.annotation.PostConstruct; import javax.ejb.EJB; import java.util.List; import jp.mydns.akanekodou.dao.CustomerDAO; import jp.mydns.akanekodou.entity.Customer; @ManagedBean public class CustomerList { @EJB private CustomerDAO dao; private List<Customer> items; @PostConstruct private void init() { items = dao.all(); } public List<Customer> getItems() { return items; } }
ManagedBean
というアノテーションによって、これが管理 Bean であることを示します。管理 Bean には、Bean のスコープを示すアノテーションを付けることもできます。たとえば session で保持しなければならない情報(ログイン情報など)が含まれる場合は SessionScoped
アノテーションを付けます。((SessionScoped
にする場合は管理 Bean は Serializable
を実装している必要があります。))省略すると RequestScoped
になります。
EJB
アノテーションで DAO のインスタンスを取得します。で、dao
のメソッドを呼び出すのですが、インスタンスはこの管理 Bean がインスタンス化されてから依存性注入で取得するので、インスタンス化が終わった後でないとメソッドを呼び出せません。そこで PostConstruct
を使ってインスタンス化が終わった直後に 1 回だけ init
メソッドを実行させます。これで items
に Customer
のリストが格納されます。
package jp.mydns.akanekodou; import javax.faces.bean.ManagedBean; import javax.faces.component.html.HtmlInputText; import javax.ejb.EJB; import jp.mydns.akanekodou.dao.CustomerDAO; import jp.mydns.akanekodou.entity.Customer; @ManagedBean public class CustomerSearch { @EJB private CustomerDAO dao; private HtmlInputText id; private Customer item; public HtmlInputText getId() { return id; } public void setId(HtmlInputText id) { this.id = id; } public Customer getItem() { return item; } public String search() { int id = Integer.parseInt((String)this.id.getValue()); item = dao.find(id); return ""; } }
HtmlInputText
は後で作成する Facelets の要素と対応するフィールドです。これは getter と setter の両方を用意してください。
String
型を返り値にもつ search
メソッドはアクションと言われるもので、フォームの値を送信した時などに実行するメソッドです。返り値には遷移先の XHTML を拡張子なして指定します。空文字を return
(もしくは return null
) した場合は遷移せずに自分自身にとどまります。ここでは入力された値を ID とみなして、ID 検索で Customer
のデータを取得してきます。送信される値は String
型なので一回 String
にキャスト(getValue
の返り値の型は Object
)し、それを整数に変換しています。
package jp.mydns.akanekodou; import javax.faces.bean.ManagedBean; import javax.faces.component.html.HtmlInputText; import javax.ejb.EJB; import java.util.List; import jp.mydns.akanekodou.dao.ProductDAO; import jp.mydns.akanekodou.entity.Product; @ManagedBean public class ProductSearch { @EJB private ProductDAO dao; private HtmlInputText keyword; private List<Product> items; public HtmlInputText getKeyword() { return keyword; } public void setKeyword(HtmlInputText keyword) { this.keyword = keyword; } public List<Product> getItems() { return items; } public String search() { items = dao.like((String)keyword.getValue()); return ""; } }
こちらも同じ要領で。