これまで、XHTMLファイル内でJavaのメソッドを呼び出す場合、呼び出すJavaのクラスに@Namedアノテーションを付与してバッキングビーンを生成してきたが、javax.faces.FACELETS_LIBRARIESにタグライブラリを追加する設定を行うことで、XHTMLファイル内で直接Javaのstaticメソッドを呼び出すことができる。
今回は、XHTMLファイル内で直接Javaのstaticメソッドを呼び出してみたので、そのサンプルプログラムを共有する。
前提条件
以下の記事の実装が完了していること。
サンプルプログラムの作成
作成したサンプルプログラムの構成は、以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
コード変換を行うユーティリティクラスの内容は以下の通りで、性別のコード値(“1”, “2”)から性別(“男”, “女”)を取得する処理を、staticメソッドで実行している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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にタグライブラリを追加する必要がある。そのための設定は、以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?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で設定している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <?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)を呼び出している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <?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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <?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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?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”)から性別(“男”, “女”)を取得する処理を削除している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | 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に、タグライブラリを追加する設定を行えばよい。