これまで、XHTMLファイル内でJavaのメソッドを呼び出す場合、呼び出すJavaのクラスに@Namedアノテーションを付与してバッキングビーンを生成してきたが、javax.faces.FACELETS_LIBRARIESにタグライブラリを追加する設定を行うことで、XHTMLファイル内で直接Javaのstaticメソッドを呼び出すことができる。
今回は、XHTMLファイル内で直接Javaのstaticメソッドを呼び出してみたので、そのサンプルプログラムを共有する。
前提条件
以下の記事の実装が完了していること。
サンプルプログラムの作成
作成したサンプルプログラムの構成は、以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
コード変換を行うユーティリティクラスの内容は以下の通りで、性別のコード値(“1”, “2”)から性別(“男”, “女”)を取得する処理を、staticメソッドで実行している。
package common; /** * コード変換を行うユーティリティクラス. */ public class CodeConvUtil { // 性別をenumで定義 private enum Sex { MAN("1", "男"), WOMAN("2", "女"); // enumのフィールドを定義 private final String code; private final String value; // enumのコンストラクタを定義 private Sex(String code, String value){ this.code = code; this.value = value; } } /** * 引数の性別のコードから性別の値を取得する. * @param sex 性別のコード * @return 性別の値 */ public static String getSexValue(String sex){ String retVal = null; // 性別が男の場合 if(Sex.MAN.code.equals(sex)){ retVal = Sex.MAN.value; // 性別が女の場合 }else if(Sex.WOMAN.code.equals(sex)){ retVal = Sex.WOMAN.value; // 性別が上記以外の場合 }else{ retVal = "不明"; } return retVal; } }
JavaのstaticメソッドをXHTMLファイルで参照できるようにするには、javax.faces.FACELETS_LIBRARIESにタグライブラリを追加する必要がある。そのための設定は、以下の通り。
<?xml version="1.0" encoding="UTF-8"?> <facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" version="2.0"> <!-- コード変換を行うユーティリティクラスをFACELETS_LIBRARIESに登録するための設定を追加 --> <namespace>http://demo.jsf.com/custom</namespace> <function> <function-name>getSexValue</function-name> <function-class>common.CodeConvUtil</function-class> <function-signature>java.lang.String getSexValue(java.lang.String)</function-signature> </function> </facelet-taglib>
javax.faces.FACELETS_LIBRARIESにタグライブラリを追加する処理は以下の通りで、web.xmlで設定している。
<?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/)を先頭に付与 --> <!-- 初期表示を入力画面(input.xhtml)から一覧画面(list.xhtml)に変更 --> <welcome-file>faces/list.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> <!-- コード変換を行うユーティリティクラスをFACELETS_LIBRARIESに登録 --> <context-param> <param-name>javax.faces.FACELETS_LIBRARIES</param-name> <param-value>/WEB-INF/custom.taglib.xml</param-value> </context-param> <!-- 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>
一覧画面・確認画面・削除確認画面の内容は以下の通りで、性別を表示する際に、追加したタグライブラリのメソッド(getSexValue)を呼び出している。
<?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://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:cust="http://demo.jsf.com/custom"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>一覧画面</title> </h:head> <h:body> <!-- 初期表示時に、UserListActionクラスのinitializeメソッドを呼び出す --> <f:metadata> <f:viewAction action="#{userListAction.initialize()}"/> </f:metadata> <p>ユーザーデータテーブル(user_data)の全データ</p> <!-- ユーザーデータが存在しない場合 --> <c:if test="${empty userListAction.userDataList}"> ユーザーデータはありません。 </c:if> <!-- ユーザーデータが存在する場合 --> <c:if test="${not empty userListAction.userDataList}"> <table border="1" cellpadding="5"> <tr> <th>ID</th> <th>名前</th> <th>生年月日</th> <th>性別</th> <th></th> <th></th> </tr> <c:forEach var="userData" items="#{userListAction.userDataList}"> <tr> <td><h:outputText value="#{userData.id}" /></td> <td><h:outputText value="#{userData.name}" /></td> <td><h:outputText value="#{userData.birthYear}年 #{userData.birthMonth}月 #{userData.birthDay}日" /></td> <td> <!-- 性別の表示にコード変換を行うユーティリティクラスを利用 --> <h:outputText value="#{cust:getSexValue(userData.sex)}" /> </td> <td> <h:form> <h:commandLink value="更新" action="#{inputFormAction.toMod()}"> <f:param name="selectId" value="#{userData.id}" /> </h:commandLink> </h:form> </td> <td> <h:form> <h:commandLink value="削除" action="#{inputFormAction.toDel()}"> <f:param name="selectId" value="#{userData.id}" /> </h:commandLink> </h:form> </td> </tr> </c:forEach> </table> </c:if> <br/><br/> <!-- データ追加ボタンを追加 --> <h:form> <h:commandButton value="データ追加" action="#{userListAction.toAdd()}" /> </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" xmlns:cust="http://demo.jsf.com/custom"> <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="#{cust:getSexValue(inputFormAction.sex)}" /> </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" xmlns:cust="http://demo.jsf.com/custom"> <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="#{cust:getSexValue(inputFormAction.sex)}" /> </td> </tr> <tr> <td align="left" valign="top">メモ:</td> <td><h:outputText value="#{inputFormAction.memo}" styleClass="lineBreakFormat" /></td> </tr> </table> <br/> <h:commandButton value="送信" action="#{inputFormAction.del()}" /> <!-- 戻るボタンを追加 --> <!-- その際、フォームの各項目値の入力チェックを省くため、immediate="true"を追加 --> <h:commandButton value="戻る" action="#{userListAction.toList()}" immediate="true" /> </h:form> </h:body> </html>
その他、以下のアクションクラスから、性別のコード値(“1”, “2”)から性別(“男”, “女”)を取得する処理を削除している。
package faces; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.enterprise.context.Conversation; import javax.enterprise.context.ConversationScoped; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.event.ComponentSystemEvent; import javax.faces.model.SelectItem; import javax.inject.Inject; import javax.inject.Named; import javax.validation.constraints.AssertTrue; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.NotEmpty; import common.CommonUtil; import common.ConversationUtil; import jpa.UserData; import jpa.UserDataJpa; import lombok.Data; import lombok.ToString; /** * 画面のフォーム値と画面遷移メソッドを定義. */ @Named(value="inputFormAction") // セッションスコープから会話スコープに変更 @ConversationScoped @Data @ToString(exclude={"birthMonthItems","birthDayItems","sexItems"}) public class InputFormAction implements Serializable { // シリアルバージョンUID private static final long serialVersionUID = 7283339629129432007L; /** ID */ private String id; /** 名前 */ @NotEmpty @Size(min=1, max=10) private String name; /** 生年月日_年 */ private String birthYear; /** 生年月日_月 */ private String birthMonth; /** 生年月日_日 */ private String birthDay; /** 性別 */ @NotEmpty(message="{sex.NotEmpty.message}") private String sex; /** メモ */ private String memo; /** 確認チェック */ @AssertTrue private Boolean checked; /** 生年月日_月(選択リスト) */ private List<SelectItem> birthMonthItems; /** 生年月日_日(選択リスト) */ private List<SelectItem> birthDayItems; /** 性別(選択リスト) */ private List<SelectItem> sexItems; /** UserDataテーブルへアクセスするJPA */ @Inject private UserDataJpa userDataJpa; /** 会話スコープマネージャー */ @Inject private Conversation conv; /** * コンストラクタ生成時に選択リストの値を設定. */ 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 toMod(){ // 会話スコープを開始 ConversationUtil.beginConv(conv); // 選択されたIDをもつユーザーデータを取得・設定 this.setSelectItem(); // 入力画面に遷移 return "toMod"; } /** * 確認画面への遷移. * @return 確認画面へのパス */ public String confirm(){ // 確認画面に遷移 return "confirm"; } /** * 入力画面に戻る. * @return 入力画面へのパス */ public String back(){ // 入力画面に戻る return "back"; } /** * 完了画面への遷移. * @return 完了画面へのパス */ public String send(){ // 画面の入力内容を登録または更新 if(id != null){ userDataJpa.update(getUserData()); }else{ userDataJpa.regist(getUserData()); } // 会話スコープを終了 ConversationUtil.endConv(conv); // 完了画面への遷移 return "send"; } /** * 削除確認画面への遷移(更新用). * @return 入力画面へのパス */ public String toDel(){ // 会話スコープを開始 ConversationUtil.beginConv(conv); // 選択されたIDをもつユーザーデータを取得・設定 this.setSelectItem(); // 削除確認画面に遷移 return "toDel"; } /** * 削除確認画面から一覧画面への遷移. * @return 一覧画面へのパス */ public String del(){ // 画面の入力内容を削除 userDataJpa.delete(getUserData()); // 会話スコープを終了 ConversationUtil.endConv(conv); // 一覧画面に遷移 return "del"; } /** * 相関チェックを実施し、エラーの場合はエラーメッセージを表示. * @param compSysEvent JSFシステムイベント */ public void validate(ComponentSystemEvent compSysEvent) { UIComponent component = compSysEvent.getComponent(); // 生年月日の年・月・日を取得する UIInput birthYearUI = (UIInput)component.findComponent("birthYear"); UIInput birthMonthUI = (UIInput)component.findComponent("birthMonth"); UIInput birthDayUI = (UIInput)component.findComponent("birthDay"); String birthYearSt = (String)birthYearUI.getLocalValue(); String birthMonthSt = (String)birthMonthUI.getLocalValue(); String birthDaySt = (String)birthDayUI.getLocalValue(); // 年・月・日がすべて空白値の場合はエラーメッセージを返す if(CommonUtil.isBlank(birthYearSt) && CommonUtil.isBlank(birthMonthSt) && CommonUtil.isBlank(birthDaySt)){ addErrorMessage("org.hibernate.validator.constraints.NotEmpty.message" , component); return; } // 生年月日が存在しない日付の場合はエラーメッセージを返す String dateStr = birthYearSt + CommonUtil.addZero(birthMonthSt) + CommonUtil.addZero(birthDaySt); if(!CommonUtil.isCorrectDate(dateStr, "uuuuMMdd")){ addErrorMessage("date.Invalid.message", component); } } /** * 引数のメッセージKeyをもつエラーメッセージを追加. * @param messageKey メッセージKey * @param component JSFコンポーネント */ private void addErrorMessage(String messageKey, UIComponent component){ FacesContext context = FacesContext.getCurrentInstance(); String message = CommonUtil.getMessage(messageKey); FacesMessage facesMessage = new FacesMessage(message, message); facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR); context.addMessage(component.getClientId(), facesMessage); context.renderResponse(); } /** * 登録時に利用するユーザー情報を生成. * @return ユーザー情報 */ private UserData getUserData(){ UserData userData = new UserData(); try{ if(this.id != null){ userData.setId(Integer.parseInt(this.id)); } userData.setName(this.getName()); userData.setSex(this.getSex()); userData.setMemo(this.getMemo()); userData.setBirthYear(Integer.parseInt(this.getBirthYear())); userData.setBirthMonth(Integer.parseInt(this.getBirthMonth())); userData.setBirthDay(Integer.parseInt(this.getBirthDay())); }catch(Exception ex){ System.err.println(ex); } return userData; } /** * 選択されたIDをもつユーザーデータを取得・設定. */ private void setSelectItem(){ // リクエストパラメータの値を取得 FacesContext fc = FacesContext.getCurrentInstance(); Map<String,String> params = fc.getExternalContext().getRequestParameterMap(); String selectId = params.get("selectId"); // 選択したIDをもつユーザーデータを取得 UserData userData = userDataJpa.getById(selectId); // フィールドの各値に取得した値を設定 if(userData != null){ id = String.valueOf(userData.getId()); name = userData.getName(); birthYear = String.valueOf(userData.getBirthYear()); birthMonth = String.valueOf(userData.getBirthMonth()); birthDay = String.valueOf(userData.getBirthDay()); sex = userData.getSex(); memo = userData.getMemo(); } } }
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/javaee-jsf-static-xhtml/demoJsf
サンプルプログラムの実行
サンプルプログラムの実行結果は、以下の記事の「サンプルプログラムの実行結果」と同じ結果となる。
例えば、一覧画面の表示内容は以下の通りで、性別が正しく変換されていることが確認できる。
要点まとめ
- XHTMLファイル内で直接Javaのstaticメソッドを呼び出すには、呼び出したいメソッドのタグライブラリの設定を、(任意値).taglib.xmlに追加した上で、web.xml内のjavax.faces.FACELETS_LIBRARIESに、タグライブラリを追加する設定を行えばよい。