はじめに
簡単なJSFのプログラミングの紹介です。自分がJDeveloperを使いながらJSFを勉強したときのものを記述しています。なお、理解するためにJDeveloperのGUI機能を敢えて利用していない作業があります。
※JDeveloper10.1.3.2で作業しました。
web.xml
JDevelperで、faces-config.xmlを作成すると、自動的にJSF用のweb.xmlとか書いてくれますが、JSFを利用する場合、FacesServlet(javax.faces.webapp.FacesServlet)の定義が必要です。
<?xml version = '1.0' encoding = 'Shift_JIS'?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee">
<description>Webアプリケーションに対する初期のweb.xmlです。</description>
<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>
<session-config>
<session-timeout>35</session-timeout>
</session-config>
<mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
</web-app>
ページ作成&実行
faces-config.xmlの「ダイアグラム」を開いて、コンポーネント・パレットから「JSF Page」をドラッグします。ここでは、名前は「index.jsp」とします。
そしてindex.jspをダブルクリックして、ウィザードが開きます。基本的にデフォルトでOKですが、「マネージドBeanでUIコンポーネントを自動公開しない」にしておきます。
この段階では faces-config.xml は何も変わっていません。index.jspの定義もないです。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
</faces-config>
一方index.jspは、次のようになっています。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=Shift_JIS"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
<title>index</title>
</head>
<body><h:form></h:form></body>
</html>
</f:view>
<@ taglib uri .... がJSFの宣言です。<f:view>タグ範囲に、これからJSFのUIコンポーネントを配置していくことになります。
動作させる場合は、このままだと真っ白画面なので、<h:form>の間にHelloWorldと書いて動かしてみます。(実行は、JSPを選んで右クリックをすると「実行」が選択できます)
<body><h:form>HelloWorld</h:form></body>
URLが
http://...../faces/index.jspのように「faces」を含んでいますが、これは<servlet-mapping>で url-patternを<url-pattern>/faces/*</url-pattern>のように定義しているためです。言い換えれば、javax.faces.webapp.FacesServlet サーブレットクラスを経由しています。
Backing Bean
Backing Beanクラス
Backing Bean(またはManaged Beanと呼ばれる)とは、アプリケーションのWeb層とビジネス層の間のデータ管理に使用されるJavaBeansです。といっても良く分からないかもしれないので、JSPに例えるとuseBean、Strutsで例えるとActionFormに似ています。画面の情報を表すBeanといったところでしょうか。
この後、ログイン画面を作るのでその画面を示すBacking Beanを作ります。
package sample.jsf.bean;
public class Login {
private String username;
private String password;
public Login() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
faces-config.xml
JavaBeanをJSFのBackingBeanとして認識するために、faces-config.xml を次のように記述します。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<managed-bean>
<managed-bean-name>LoginBean</managed-bean-name>
<managed-bean-class>sample.jsf.bean.Login</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
manage-beanタグに、managed-bean-name、managed-bean-class、managed-bean-scopeを定義します。managed-bean-scopeは、Backing Beanの生存期間を示します。
| managed-bean-scope |
意味 |
| application |
そのWebアプリケーションが起動してから終了するまで |
| session |
セッションが有効なあいだ |
| request |
(HTTPの)要求から応答まで |
| none |
スコープには属さない |
index.jspに次の記述をします。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=Shift_JIS"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
<title>index</title>
</head>
<body><h:form>
<table>
<tr>
<td nowrap>ユーザ名</td>
<td><h:inputText id="username" value="#{LoginBean.username}" /></td>
</tr>
<tr>
<td nowrap>パスワード</td>
<td><h:inputSecret id="password" value="#{LoginBean.password}" /></td>
</tr>
</table>
<h:commandButton value="ログイン" />
</h:form>
<p>
ユーザ名:<h:outputLabel value="#{LoginBean.username}"/>、
パスワード :<h:outputLabel value="#{LoginBean.password}"/>
</p>
</body>
</html>
</f:view>
<h:inputText>と<h:inputSecret>は、valueに #{LoginBean.username}や#{LoginBean.password} を指定することで、フォームから入力した値がBacking Beanに設定されます。<h:outputLabel>には、Backing Beanの値を出力するようにしています。
ユーザ名とパスワードにaaaa、bbbbを入れて実行すると次のようになります。
画面遷移
faces-config.xml
faces-config.xmlに、<navigation-rule>で画面遷移を定義します。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<managed-bean>
<managed-bean-name>LoginBean</managed-bean-name>
<managed-bean-class>sample.jsf.bean.Login</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/index.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/success.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/index.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
上記は、sucessの場合は success.jsp 画面、failureの場合は index.jsp に戻ることを意味しています。
Backing Beanクラス
Backing Beanクラスに、Strutsで言うところのActionに相当するメソッドを追加します。Webのフォーム画面でSubmitボタンを押下すると呼ばれるメソッドです。
package sample.jsf.bean;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
public class Login {
< setter,getter などは、省略 >
public String authenticate() {
if (this.username.equals(this.password)) {
return "success";
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
request.setAttribute("loopback", Boolean.TRUE);
return "failure";
}
}
}
authenticate というメソッドを追加して、ユーザ名とパスワードが同じであれば success を、異なれば failure の文字列を返しています。
また、failure の場合にindex.jsp 側で、失敗したことを判別するために、HttpServletRequest.setAttributeでフラグを渡しています。Backing Beanで、HttpServletRequestのインスタンスを取得する場合、次のように書くと取得できます。
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalContext.getRequest();
呼び出しフォーム(index.jsp)
Backing Beanのメソッドを呼び出すためにindex.jsp を少し書き換えます。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=Shift_JIS"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
<title>index</title>
</head>
<body><h:form>
<table>
<tr>
<td nowrap>ユーザ名</td>
<td><h:inputText id="username" value="#{LoginBean.username}" /></td>
</tr>
<tr>
<td nowrap>パスワード</td>
<td><h:inputSecret id="password" value="#{LoginBean.password}" /></td>
</tr>
</table>
<h:commandButton value="ログイン" action="#{LoginBean.authenticate}" />
</h:form>
<%
Boolean loopback = (Boolean)request.getAttribute("loopback");
if (loopback != null && loopback.booleanValue()) {
%>
<p><font color="Red">ユーザ名、又はパスワードが間違えています。</font></p>
<%
}
%>
</body>
</html>
</f:view>
先ほど定義したBacking Beanのメソッドを呼び出すために、h:commandButtonタグで次のように定義しています。
<h:commandButton value="ログイン" action="#{LoginBean.authenticate}" />
また、Backing Beanの authenticate メソッドにおいて、認証に失敗したことを示すsetAttribute("loopback", Boolean.TRUE) しているので、その値を判断するためのロジック を追加しています。
その他
バリデーション
実装方法
ユーザ名、パスワードの入力チェック(バリデート)をしてみます。それぞれ次のような規則とします。
- ユーザ名 … 必須。最大5文字
- パスワード … 必須。最小5文字
この規則をJSFのバリデーション機能を利用して実現するために、index.jsp を少し改良します。ユーザ名のh:inputTextタグ を例に説明します。
<tr>
<td nowrap>ユーザ名</td>
<td><h:inputText id="username" value="#{LoginBean.username}" required="true">
<f:validateLength maximum="5"/></h:inputText></td>
<td><h:message for="username" /></td>
</tr>
必須チェックについては、h:inputTextタグ の属性に、require="true" を指定しています。文字の長さチェックは、<f:validateLength maximum="5"/>で指定しています。
バリデートは自分で自作することも可能ですので、既存で用意されているものでは不十分な場合は、開発する方法もあるでしょう。
次に、チェックでエラーになったときの、メッセージは、<h:message for="username" /> の部分で表示されます。<h:messages />でも表示できますが、他のフィールドのメッセージもすべて列挙するので、複数チェック項目がある場合は、どこで間違えたか良く分からないかもしれません。
また、メッセージはJSFで用意している固定のものになりますが、自分でメッセージ作成することも可能です。
h:inputSecrettタグについても基本的にはh:inputTextと同様です。
以下は、改良後の index.jsp 全体です。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=Shift_JIS"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"/>
<title>index</title>
</head>
<body><h:form>
<table>
<tr>
<td nowrap>ユーザ名</td>
<td><h:inputText id="username" value="#{LoginBean.username}" required="true">
<f:validateLength maximum="5"/></h:inputText></td>
<td><h:message for="username" /></td>
</tr>
<tr>
<td nowrap>パスワード</td>
<td><h:inputSecret id="password" value="#{LoginBean.password}" required="true">
<f:validateLength minimum="5"/></h:inputSecret></td>
<td><h:message for="password" /></td>
</tr>
</table>
<h:commandButton value="ログイン" action="#{LoginBean.authenticate}" />
</h:form>
<%
Boolean loopback = (Boolean)request.getAttribute("loopback");
if (loopback != null && loopback.booleanValue()) {
%>
<p><font color="Red">ユーザ名、又はパスワードが間違えています。</font></p>
<%
}
%>
</body>
</html>
</f:view>
実行例
イベントハンドリング
あとで。
最終更新:2007年09月19日 19:38