昨日書いた
はじめてのWindows Azure ~SQLデータベース作成からNetBeansでの接続まで~
にて、AzureでSQLデータベースを生成して、NetBeansのデータベースサービスと簡単に連携できました。
ということは、ここからNetBeansの自動生成機能を使えば簡単にデータベース処理のWebアプリが作れるわけで、やってみました。
ここに来るとあまりAzure関係ないですね…(^^;
ちなみにWidnows 8 Proの64bitでJDK8、NetBeans7.4でGlassFish4.0にて行いました。
NetBeansで新規プロジェクト作成
「ファイル」->「新規プロジェクト」を選択します。
Mavenを使わなくてもいいですが、依存性管理が簡単なので今回はMavenのパターンで書きます。「Maven」->「Webアプリケーション」を選択します。
プロジェクト名を適当に入力します。今回はサンプルなので、あとはそのまま。
Java EE7でいきます。GlassFishは4.0です。
これでプロジェクトができます。
JPAのエンティティ・クラスを生成
プロジェクトができたら、パッケージで右クリックして「新規」を選択します。
「持続性」->「データベースからのエンティティ・クラス」を選択します。
「新しいデータ・ソース」を選択します。
JNDI名を適当に入れて、データベース接続で昨日の手順で作った名称のデータベース接続を選択します。
すると「使用可能な表」にEmployeeテーブルがみえるので、追加を押して以下状態とします。
NamedQuery不要であればチェック外したり、ですが、ここではデフォルトのままにします。
コレクション型をjava.util.Listにして、終了しました。
これでEmployeeエンティティクラスが生成されました。
トランザクション処理用のEJBを生成
先と同じように、パッケージで右クリックして「新規」を選択し、「エンタープライズJavaBeans」から「エンティティ・クラスのセッションBean」を選択します。
使用可能なエンティティ・クラスに先ほど自動生成されたEmployeeクラスがみえるので「追加」します。
本来はパッケージ分けたほうが良いですが、今回はサンプルなのでそのままにして進めます。
これでAbstractFacade.javaとEmployeeFacade.javaが自動生成されました。
AbstractFacadeはCRUD処理+アルファを含んだ抽象クラスで、EmployeeFacadeはそれを継承して生成された具象クラスで、以下のようなコードが生成されます。
package jp.co.hoge.azuredbsample;
import java.util.List;
import javax.persistence.EntityManager;
@author
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
package jp.co.hoge.azuredbsample;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@author
@Stateless
public class EmployeeFacade extends AbstractFacade<Employee> {
@PersistenceContext(unitName = "jp.co.hoge_AzureDBsample_war_1.0PU")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
public EmployeeFacade() {
super(Employee.class);
}
}
管理対象ビーン(Backing Bean)を生成します。
画面の入力情報などを管理するクラスを生成します。
前と同じ手順で以下ウィンドウを開き、「JavaServer Faces」から「JSF管理対象Bean」を選択します。
Java EE7ではJSF管理対象ではなくCDI管理対象が推奨なのですが、この手順で作ります。(このMavenの流れでCDI管理対象作れる方法ありましたっけ??)
生成されたコードはJSF管理対象になっています。
@ManagedBeanを@Namedに書き換え、@ViewScopedは一旦パッケージ名を消して、javax.faces.view.ViewScopedをインポートします。ここが本当にややこしいよなぁ…。
これで管理対象ビーンクラスが生成されます。
今回のサンプルでは、Mavenの依存性でLombokを入れておきます。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.12.2</version>
</dependency>
コードは以下のように、IDと名前だけ受け取るようにして、それをInsertする処理を1つだけ書いておきます。生成したEJBもInjectしておきます。
ここでやっと初めてコード書いてます(^^;
package jp.co.hoge.azuredbsample;
import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import lombok.Getter;
import lombok.Setter;
@author
@Named
@ViewScoped
public class EmployeeBean implements Serializable{
@Inject
private EmployeeFacade empDbFacade;
@Getter @Setter
private int id;
@Getter @Setter
private String name;
public void insertNewEmployee(){
Employee emp = new Employee(id, name);
empDbFacade.create(emp);
}
}
JSFでページを生成する。
最後は画面を作るだけです。デフォルトである「index.html」を利用してもよいですが、ここでは一旦削除して、Webページを右クリックして「新規」から以下を選びました。
ファイル名はindexにしておいて終わります。
生成されたindex.xhtmlは以下で定義しました。
<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:inputText value="#{employeeBean.id}" />
<h:inputText value="#{employeeBean.name}" />
<h:commandButton value="Insert" action="#{employeeBean.insertNewEmployee()}" />
</h:form>
</h:body>
</html>
実行してみる
実行すると…
こんなエラーが最初でたのですが、これは昨日作ったAzureのSQLデータベースとNetBeansの接続設定で、JDBCのURLのみを入れたためでした。
今回作成したNetBeansプロジェクト内の「その他ソース」->「setup」に「glassfish-resources.xml」がありますが、そこの設定を確認して適切に修正してください。valueが空白になっている値などがあったので、私の場合は昨日作ったUser名をvalueに設定しました。(実際には、URLで全て書いてるからこのプロパティごといらない?のかも)
これらを修正して、再度実行するとページが表示されました。画面がちょっと手抜きすぎますが(^^;
IDが1のEmployeeは昨日手動でinsertしてるので、2として名前も入れてボタンを押します。するとinsertされます。
せっかくなのでAzureから確認してみます。
おお、追加されてる!
ということで、これまたあっさりですね。うーん楽だ。