はじめに
この記事は「JavaEE Advent Calendar 2012」の12日目の記事となります。
昨日は@matsumanaさんによる「NetBeansでJavaEE6開発する時にHotDeploy可能なプロジェクトタイプ」でした。
明日は@noriandさんとなります。
簡単に自己紹介
入社8年目のエンジニアです。入社以来、1つの基幹業務システム開発プロジェクトに従事し、開発は主に.NET C#2.0&WindowsFormでした。
今年から、いよいよ別の新しいプロジェクトに参画!となったのですが、Formから一転Web開発、しかもC# ASP.NETではなくJavaEEを始めることになりました。
8月頃から触り初め、勉強メモがてらに日記を付け始めたのですが、このようなイベントへお声かけを頂いて嬉しい反面とても緊張してます(^^;
Java初心者なので、他の方々の記事に比べると色々至らぬ点もあると思いますが宜しくお願い致しますm(_ _)m
PrimeFacesとは
前置きが長くなりましたが、私はJSFベースのリッチUIコンポーネントである「PrimeFaces」の紹介をベースに、様々あるコンポーネントの中から「ちょっと便利なコンポ達」を紹介させて頂きたいと思います。
PrimeFacesはPrime Teknolojiというトルコのソフトウェア会社(特にアジャイル開発やJavaEE向けのコンサルを行っているようです)により提供されています。Apache License V2ライセンスのOSSとなります。
JavaEEは金魚本(Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava)で勉強を初め、JSFはそこで初めて知りました。
その後、実際に画面サンプルなどを作ってみたのですが、実際に業務システムで使うには何らかの画面部品が欲しいなと思い、調べてみたところ様々なものがあることを知りました。
当時調べたメモを引きずりだすと以下のようなライブラリがありました。
他にもまだ色々あると思うのですが、各々のデモやShowcaseをみたり、実際に落として触ったりした中で、私はPrimeFacesに惹かれました。
とにかくコンポーネントの種類が豊富なことが一番魅力的で、実際海外での利用も多いようで情報も多くあったため、PrimeFacesを選びました。
セットアップ
NetBeans&GlassFishを使ってPrimeFacesをセットアップする方法は先日まとめましたので、そちらを見て頂ければと思います。
本題:ちょっと便利なコンポ達
近年、デザインの良いホームページやスマホ・タブレット等の普及により、ユーザさんのUIに対する目がとても肥えている感じがします。
なので「まあ、基幹業務系システムなので見た目より中身が肝心でして…」なんて回避も難しく、見た目の印象が悪いだけで
「ダサい→使えなさそう」と負のイメージが最初から抱かれ、そうなると「システムバグがでる→ほらみたことか→やっぱ使えない→なんで業務システム刷新したんだ」
なんて流れにつながりかねません(-_-;くわばらくわばら
いずれにせよリッチな画面を手軽に作れれば嬉しく、幸いPrimeFacesにはそういったコンポーネントがたくさんあるように思います。
今日はその中でも「これはちょっと便利だ」「かゆい所に手が届くな」というコンポーネントにフォーカスを当てて紹介させて頂きます。
Password
パスワードマスクは普通にあるものですが、PrimeFacesのコンポでは属性の設定を加えるだけで強度を出すこともできます。
feedback属性をtrueに指定すればOKです。メッセージを日本語にするには以下のように記述します。
<p:password id="pswd" maxlength="10" feedback="true"
promptLabel="入力して下さい" weakLabel="パスワード強度:弱い"
goodLabel="パスワード強度:普通" strongLabel="パスワード強度:強い" />
feedback="false"の場合
feedback="true"で未入力の場合
feedback="true"でパスワード強度weakの場合
feedback="true"でパスワード強度goodの場合
feedback="true"でパスワード強度strongの場合
強度判定の詳細に関しては情報を(探したのですが)拾えていません。感触的には長さ、組合せ、記号有無などをみて判定してそうです。
AjaxStatus
Ajaxによる通信時、処理完了までの間に表示されるクルクルを簡単に設置できます。
<p:ajaxStatus id="stsAjax">
<f:facet name="start">
<p:graphicImage id="imgLoader" value="/resources/images/ajax-loader.gif" />
</f:facet>
<f:facet name="complete">
<h:outputLabel value="" />
</f:facet>
</p:ajaxStatus>
クルクルのgif画像は
http://www.ajaxload.info/
等から簡単に作れるので、その画像を指定すればチャチャっと設置できます。
ただしAjax以外(コンポーネントの属性でajax="false"とした場合等)では効かないので注意して下さい。
Watermark
検索のテキストボックス背景にうっすら文字…的なものを簡単に実現できます。
<p:watermark id="wtmSearch" for="frm:txt"
value="検索するキーワードを入力して下さい" />
BlockUI
ボタン連打などのガード対応をプログラムで対応せずともViewで防げます。
<p:blockUI id="blcLogin" block="pnl" widgetVar="bui"/>
<p:commandButton id="btnLogin" value="ログイン" ajax="false" action="#{loginBean.login()}" onclick="bui.show()" />
ボタンを押下した後、次ページに遷移するまでの間、上図のようにグレー色になって、クリックとかできない状態となります。
ページ遷移以外でも、保存ボタンや削除ボタンでも有効です。
ConfirmDialog
確認ダイアログです。
JSFの複合コンポーネントも普通に*1適用できるので、例えば確認ダイアログで
・「OK」の1ボタン
・「はい」「いいえ」の2ボタン
・「はい」「いいえ」「キャンセル」の3ボタン
等を1つのコンポーネントにすることもできます。
こんな感じに定義しています。
<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<composite:interface>
<composite:attribute name="btnFirstActionListener" targets="btnFirst" default="return true;" shortDescription="1つ目のボタン押下時の処理" />
<composite:attribute name="btnSecondActionListener" targets="btnSecond" default="return true;" shortDescription="2つ目ボタン押下時の処理" />
<composite:attribute name="btnThirdActionListener" targets="btnThird" default="return true;" shortDescription="3つ目ボタン押下時の処理" />
<composite:attribute name="buttonCount" default="2" shortDescription="表示するボタン数(1:OKボタン|2:Yes,Noボタン|3:Yes,No,Cancelボタン)" />
<composite:attribute name="header" shortDescription="ヘッダ文言" />
<composite:attribute name="message" shortDescription="メッセージ" />
<composite:attribute name="severity" default="alart" targets="dlg" shortDescription="メッセージアイコン(info|alart)" />
<composite:attribute name="btnFirstUpdate" targets="btnFirst" shortDescription="1つ目のボタン押下時の更新対象コンポーネントID" />
<composite:attribute name="btnSecondUpdate" targets="btnSecond" shortDescription="2つ目のボタン押下時の更新対象コンポーネントID" />
<composite:attribute name="btnThirdUpdate" targets="btnThird" shortDescription="3つ目のボタン押下時の更新対象コンポーネントID" />
<composite:attribute name="btnFirstValue" shortDescription="1つ目のボタン表示名" />
<composite:attribute name="btnSecondValue" shortDescription="2つ目のボタン表示名" />
<composite:attribute name="btnThirdValue" shortDescription="3つ目のボタン表示名" />
<composite:attribute name="widgetVar" shortDescription="ウィジェットID" />
</composite:interface>
<composite:implementation>
<p:confirmDialog id="dlg" message="#{cc.attrs.message}"
header="#{cc.attrs.header}" severity="#{cc.attrs.severity}" widgetVar="#{cc.attrs.widgetVar}">
<c:choose>
<c:when test="#{cc.attrs.buttonCount==1}">
<p:commandButton id="btnFirst" value="#{cc.attrs.btnFirstValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()"
actionListener="#{cc.attrs.btnFirstActionListener}" update="#{cc.attrs.btnFirstUpdate}" />
</c:when>
<c:when test="#{cc.attrs.buttonCount==3}">
<p:commandButton id="btnFirst" value="#{cc.attrs.btnFirstValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()"
actionListener="#{cc.attrs.btnFirstActionListener}" update="#{cc.attrs.btnFirstUpdate}" />
<p:commandButton id="btnSecond" value="#{cc.attrs.btnSecondValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()"
actionListener="#{cc.attrs.btnSecondActionListener}" update="#{cc.attrs.btnSecondUpdate}"/>
<p:commandButton id="btnThird" value="#{cc.attrs.btnThirdValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()" update="#{cc.attrs.btnThirdUpdate}"/>
</c:when>
<c:otherwise>
<p:commandButton id="btnFirst" value="#{cc.attrs.btnFirstValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()"
actionListener="#{cc.attrs.btnFirstActionListener}" update="#{cc.attrs.btnFirstUpdate}" />
<p:commandButton id="btnSecond" value="#{cc.attrs.btnSecondValue}"
oncomplete="#{cc.attrs.widgetVar}.hide()" update="#{cc.attrs.btnSecondUpdate}"/>
</c:otherwise>
</c:choose>
</p:confirmDialog>
</composite:implementation>
</html>
利用する側
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:k="http://java.sun.com/jsf/composite/component"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html">
<k:commandButtonAjax id="btnOkInfoDialog" value="1ボタンダイアログ(Info)" onclick="okInfoDlg.show();" />
<k:confirmDialog id="dlgOkInfo" buttonCount="1"
message="message" header="header" severity="info" widgetVar="okInfoDlg" btnFirstValue="OK" />
<k:commandButtonAjax id="btnOkAlertDialog" value="1ボタンダイアログ(Info)" onclick="okAlertDlg.show();" />
<k:confirmDialog id="dlgOkAlert" buttonCount="1"
message="message" header="header" severity="alert" widgetVar="okAlertDlg" btnFirstValue="OK" />
<k:commandButtonAjax id="btnOkDialog" value="2ボタンダイアログ" onclick="yesNoDlg.show();" />
<k:confirmDialog id="dlgYesNo" buttonCount="2"
message="message" header="header" severity="alert" widgetVar="yesNoDlg" btnFirstValue="Yes" btnSecondValue="No" />
<k:commandButtonAjax id="btnOkDialog" value="3ボタンダイアログ" onclick="cancelDlg.show();" />
<k:confirmDialog id="dlgCancel" buttonCount="3"
message="message" header="header" severity="alert" widgetVar="cancelDlg"
btnFirstValue="Yes" btnSecondValue="No" btnThirdValue="Cancel" />
Focus
地味ですが、フォーカスの位置を決められます。
<p:focus context="pnl" />
パネルの中の最初のテキストボックスにフォーカスが当たります。
IdleMonitor
一定時間(timeout属性で指定した時間)放置プレイするとイベント起こします。自動ログオフの警告などで使えそうです。
<p:idleMonitor timeout="20000" onidle="idleDlg.show()" />
<k:confirmDialog widgetVar="idleDlg" message="残りxx分でログアウトします。"
btnFirstValue="はい" btnSecondValue="いいえ" btnFirstActionListener="this.hide()"/>
Messages
メッセージは種別ごとに色分けされて表示されます。
xhtmlはこんな感じで、ボタンイベントでメッセージを突っ込んでみます。
<h:body>
<h:form id="frm">
<p:messages id="mes"/>
<p:commandButton update="frm:mes" value="ボタン" action="#{messageBean.message()}" />
</h:form>
</h:body>
バッキングビーンはこんな感じです。
package jp.co.hoge.messages;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
@Named(value = "messageBean")
@RequestScoped
public class MessageBean {
public MessageBean() {
}
public void message(){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Infoです","Infoです"));
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,"Warnです","Warnです"));
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Errorです","Errorです"));
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL,"Fatalです","Fatalです"));
}
}
ErrorとFatalは色が同じでマークが違うだけですね。
ThemeSwitcher
いくつかデザインの異なるテーマが定義されていて、画面デザインをユーザさんが自由に選択!なんかもできそうです。
上記で作った確認ダイアログをいくつかのテーマで表示すると以下のようになります。
結構見た目で印象変わりますね(^^)テキストボックスの角の丸み具合やグレーアウトしてる背景などもテーマによって異なります。
PrimeFacesのShowcaseサイトの右上にも付いているので、各コンポーネントの細かいデザイン具合はそこでご確認ください。
また、自分でもテーマは作成できる(まだ作ったことないのですが)ようですので、興味がある方はPrimeFacesのサイトから
ダウンロードできるドキュメントを参照して下さい。
BreadCrumb
最後はパンくずリストです。
ここまで、ほとんどがビューのxhtmlのみで、Javaプログラムが非常に少ない!ので、最後だけプログラムでコンポーネントを操作した例を掲載します。
xhtmlはこんな感じです。
<h:body>
<f:view>
<h:form id="breadFrm">
<p:breadCrumb id="testBread" binding="#{componentBindingBean.bread}" />
<p:inputText id="testInputText" binding="#{componentBindingBean.inputText}" />
<p:breadCrumb />
</h:form>
</f:view>
</h:body>
プログラムで入力テキストに文字を入れたり、パンくずのリスト項目を追加してみます。
package jp.co.hoge.binding;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import org.primefaces.component.breadcrumb.BreadCrumb;
import org.primefaces.component.inputtext.InputText;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;
@Named(value="compBindingBean")
@RequestScoped
public class ComponentBindingBean implements Serializable{
private InputText inputText;
private BreadCrumb bread;
public InputText getInputText() {
return inputText;
}
public void setInputText(InputText inputText) {
this.inputText = inputText;
}
public BreadCrumb getBread() {
return bread;
}
public void setBread(BreadCrumb bread) {
this.bread = bread;
}
public ComponentBindingBean() {
inputText = new InputText();
inputText.setValue("JavaEE Advent Calendar 12日目");
bread = new BreadCrumb();
MenuModel menuModel = new DefaultMenuModel();
MenuItem home = new MenuItem();
home.setId("breadItemHome");
home.setValue("ほーむ");
home.setUrl("home");
menuModel.addMenuItem(home);
MenuItem item1 = new MenuItem();
item1.setId("breadItem1");
item1.setValue("ぱんくず1");
item1.setUrl("menu1");
menuModel.addMenuItem(item1);
MenuItem item2 = new MenuItem();
item2.setId("breadItem2");
item2.setValue("ぱんくず2");
item2.setUrl("menu2");
menuModel.addMenuItem(item2);
bread.setModel(menuModel);
bread.buildMenuFromModel();
}
}
実行するとこんな感じです↓
さいごに
なお、上記含むPrimeFaces全てのコンポーネントはこちらで確認&触れます→ PrimeFacesのShowcase
是非一度触ってみて下さい!
明日は@noriandさんです。よろしくお願いします。