これまで、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に、タグライブラリを追加する設定を行えばよい。





