JSF(JavaServer Faces)プロジェクトを利用して、JavaベースのWebアプリケーションを作成することができる。
今回は、入力画面・確認画面・完了画面の3画面を含み、HTMLオブジェクトとしてテキストボックス・ラジオボタン・チェックボックス等を含むWEBアプリケーションを作成してみたので、そのサンプルプログラムを共有する。
前提条件
下記記事に記載した、JSFプロジェクトの作成が完了していること。
サンプルプログラムの作成
作成したサンプルプログラムの構成は、以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
web.xmlの内容は以下の通りで、初期表示画面をinput.xhtmlに設定し、テキスト・テキストエリアの文字化け防止用Filterを追加している。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>demoJsf</display-name> <welcome-file-list> <!-- 画面遷移先でJSFタグを利用できるよう、Faces ServletのURL(faces/)を先頭に付与 --> <welcome-file>faces/input.xhtml</welcome-file> </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <!-- JSFでのテキスト・テキストエリアの文字化け防止用Filterを設定 --> <filter> <filter-name>Encoding</filter-name> <filter-class>common.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
また、テキスト・テキストエリアの文字化け防止用Filterの内容は、以下の通り。
package common; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * 文字コードをweb.xmlに記載したものに設定するためのフィルタ. */ public class EncodingFilter implements Filter { /** 文字コード */ private String encoding; @Override public void doFilter(ServletRequest request , ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); chain.doFilter(request, response); } @Override public void init(FilterConfig config) throws ServletException { encoding = config.getInitParameter("encoding"); } @Override public void destroy() {} }
さらに、入力画面(input.xhtml)、確認画面(confirm.xhtml)、完了画面(complete.xhtml)の内容は、以下の通り。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>入力画面</title> </h:head> <h:body> <p>下記必要事項を記載の上、「確認」ボタンを押下してください。</p><br/> <h:form> <table border="0"> <tr> <td align="left" valign="top">名前:</td> <td><h:inputText value="#{inputFormAction.name}" /></td> </tr> <tr> <td align="left" valign="top">生年月日:</td> <td> <h:inputText value="#{inputFormAction.birthYear}" size="4" maxlength="4" />年 <h:selectOneMenu value="#{inputFormAction.birthMonth}"> <f:selectItems value="#{inputFormAction.birthMonthItems}"/> </h:selectOneMenu>月 <h:selectOneMenu value="#{inputFormAction.birthDay}"> <f:selectItems value="#{inputFormAction.birthDayItems}"/> </h:selectOneMenu>日 </td> </tr> <tr> <td align="left" valign="top">性別:</td> <td> <h:selectOneRadio value="#{inputFormAction.sex}"> <f:selectItems value="#{inputFormAction.sexItems}"/> </h:selectOneRadio> </td> </tr> <tr> <td align="left" valign="top">メモ:</td> <td><h:inputTextarea value="#{inputFormAction.memo}" cols="40" rows="6" /></td> </tr> <tr> <td align="left" valign="top">入力確認:</td> <td><h:selectBooleanCheckbox value="#{inputFormAction.checked}" /></td> </tr> </table> <br/> <h:commandButton value="確認" action="#{inputFormAction.confirm()}" /> </h:form> </h:body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>確認画面</title> <h:outputStylesheet library="css" name="demoJsf.css"/> </h:head> <h:body> <p>入力内容を確認し、問題なければ「送信」ボタンを押下してください。</p><br/> <h:form> <table border="0"> <tr> <td align="left" valign="top">名前:</td> <td><h:outputText value="#{inputFormAction.name}" /></td> </tr> <tr> <td align="left" valign="top">生年月日:</td> <td><h:outputText value="#{inputFormAction.birthYear}年 #{inputFormAction.birthMonth}月 #{inputFormAction.birthDay}日" /></td> </tr> <tr> <td align="left" valign="top">性別:</td> <td><h:outputText value="#{inputFormAction.sexLabel}" /></td> </tr> <tr> <td align="left" valign="top">メモ:</td> <td><h:outputText value="#{inputFormAction.memo}" styleClass="lineBreakFormat" /></td> </tr> <tr> <td align="left" valign="top">確認チェック:</td> <td> <h:outputText value="確認済" rendered="#{inputFormAction.checked}" /> <h:outputText value="未確認" rendered="#{inputFormAction.checked == false}" /> </td> </tr> </table> <br/> <h:commandButton value="送信" action="#{inputFormAction.send()}" /> <h:commandButton value="戻る" action="#{inputFormAction.back()}" /> </h:form> </h:body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>完了画面</title> </h:head> <h:body> <p>お申し込みが完了しました。</p> </h:body> </html>
また、各画面のForm値と画面遷移処理を定義したクラスの内容は以下の通りで、入力画面・確認画面から呼び出されている。
package faces; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.enterprise.context.SessionScoped; import javax.faces.model.SelectItem; import javax.inject.Named; import common.CommonUtil; /** * 画面のフォーム値と画面遷移メソッドを定義. */ // @Namedアノテーションは、JSFのXHTMLファイルから#{inputFormAction}で // Javaクラスを参照できるようにしている(→バッキングビーン) // @SessionScopedアノテーションは、このバッキングビーンの生存期間を // セッションに設定している @Named(value="inputFormAction") @SessionScoped public class InputFormAction implements Serializable { // シリアルバージョンUID private static final long serialVersionUID = 7283339629129432007L; /** 名前 */ private String name; /** 生年月日_年 */ private String birthYear; /** 生年月日_月 */ private String birthMonth; /** 生年月日_日 */ private String birthDay; /** 性別 */ private String sex; /** 性別(ラベル) */ private String sexLabel; /** メモ */ private String memo; /** 確認チェック */ private String checked; /** 生年月日_月(選択リスト) */ private List<SelectItem> birthMonthItems; /** 生年月日_日(選択リスト) */ private List<SelectItem> birthDayItems; /** 性別(選択リスト) */ private List<SelectItem> sexItems; /** * コンストラクタ生成時に選択リストの値を設定. */ public InputFormAction(){ // 生年月日_月(選択リスト) birthMonthItems = new ArrayList<SelectItem>(); birthMonthItems.add(new SelectItem("", "")); for(Integer i = 1; i <= 12; i++){ birthMonthItems.add(new SelectItem(String.valueOf(i), String.valueOf(i))); } // 生年月日_日(選択リスト) birthDayItems = new ArrayList<SelectItem>(); birthDayItems.add(new SelectItem("", "")); for(Integer i = 1; i <= 31; i++){ birthDayItems.add(new SelectItem(String.valueOf(i), String.valueOf(i))); } // 性別(選択リスト) sexItems = new ArrayList<SelectItem>(); sexItems.add(new SelectItem(String.valueOf(1),"男")); sexItems.add(new SelectItem(String.valueOf(2),"女")); } /** * 確認画面への遷移. * @return 確認画面へのパス */ public String confirm(){ // 性別(ラベル)を設定 if(!CommonUtil.isBlank(sex)){ this.setSexLabel(this.getSexItems() .get(Integer.parseInt(this.getSex())-1).getLabel()); } // Formに設定された値を出力 System.out.println(this.toString()); // 確認画面に遷移、ただし、遷移先URLを正しく表示し画面遷移を安定させるため、 // ?faces-redirect=trueを付与し、フォワードからリダイレクトに変更している return "confirm.xhtml?faces-redirect=true"; } /** * 入力画面に戻る. * @return 入力画面へのパス */ public String back(){ // 入力画面に戻る return "input.xhtml?faces-redirect=true"; } /** * 完了画面への遷移. * @return 完了画面へのパス */ public String send(){ // 確認画面に表示された値を出力 System.out.println(this.toString()); // 完了画面に遷移 return "complete.xhtml?faces-redirect=true"; } @Override public String toString() { return "InputForm [name=" + name + ", birthYear=" + birthYear + ", birthMonth=" + birthMonth + ", birthDay=" + birthDay + ", sex=" + sex + " sexLabel=" + sexLabel + ", memo=" + memo + ", checked=" + checked + "]"; } // 以下はGetter/Setterメソッド // JSFのXHTMLファイルから各メンバ変数にアクセスするために必要 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getBirthYear() { return birthYear; } public void setBirthYear(String birthYear) { this.birthYear = birthYear; } public String getBirthMonth() { return birthMonth; } public void setBirthMonth(String birthMonth) { this.birthMonth = birthMonth; } public String getBirthDay() { return birthDay; } public void setBirthDay(String birthDay) { this.birthDay = birthDay; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getSexLabel() { return sexLabel; } public void setSexLabel(String sexLabel) { this.sexLabel = sexLabel; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } public String getChecked() { return checked; } public void setChecked(String checked) { this.checked = checked; } public List<SelectItem> getBirthMonthItems() { return birthMonthItems; } public void setBirthMonthItems(List<SelectItem> birthMonthItems) { this.birthMonthItems = birthMonthItems; } public List<SelectItem> getBirthDayItems() { return birthDayItems; } public void setBirthDayItems(List<SelectItem> birthDayItems) { this.birthDayItems = birthDayItems; } public List<SelectItem> getSexItems() { return sexItems; } public void setSexItems(List<SelectItem> sexItems) { this.sexItems = sexItems; } }
さらに、確認画面(confirm.xhtml)で読んでいるCSSファイル、共通ユーティリティクラスの内容は、以下の通り。
.lineBreakFormat{ /* 改行コードをbrタグに変換し表示する */ /* 空白文字はそのまま残す */ white-space: pre; }
package common; /** * 共通ユーティリティクラス. */ public class CommonUtil { /** * 引数で指定した文字列がNULL,空文字,空白のみかどうかをチェックする. * @param cs 文字列 * @return 判定結果 */ public static boolean isBlank(final CharSequence cs) { final int strLen = length(cs); if (strLen == 0) { return true; } for (int i = 0; i < strLen; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } /** * 引数で指定した文字列の長さを返却する. * @param cs 文字列 * @return 文字列の長さ */ public static int length(final CharSequence cs) { return cs == null ? 0 : cs.length(); } }
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/javaee-jsf-web-somescreen/demoJsf
サンプルプログラムの実行結果
サンプルプログラムの実行結果は以下の通り。
1) GlassFishサーバーを起動後、Webブラウザ上で「http:// (ホスト名):(ポート番号)/(Webアプリケーションのプロジェクト名)/」とアクセスする。
2) 以下のように、データを指定し「確認」ボタンを押下すると、確認画面に入力画面の内容が表示される。さらに「戻る」ボタンを押下すると、入力画面に戻り入力値が復旧されることが確認できる。
3) 以下のように、メモを入力しないで「確認」ボタンを押下した場合も、確認画面に入力画面の内容が表示される。さらに「送信」ボタンを押下すると、完了画面に遷移することが確認できる。
4) 2)3)の動作で、以下のように、コンソールに赤枠のログが出力されることが確認できる。
要点まとめ
- JSF(JavaServer Faces)プロジェクトを利用して、JavaベースのWebアプリケーションを作成することができる。
- JSFのXHTMLファイルからJavaクラスやメンバ変数を参照できるようにする(→バッキングビーンの生成)には、Javaクラスに@Namedアノテーションを付与し、メンバ変数のGetter/Setterメソッドを付与する必要がある。
- JSFのXHTMLファイルからバッキングビーンを参照するには、#{バッキングビーン名.メンバ変数}、#{バッキングビーン名.メソッド名()}というEL式を利用する。
- JSFのテキスト/テキストエリアの文字化けを防止するには、文字化け防止用のFilterを追加する。