JSF2.2入門 第2回ユーザー入力

kanban2

katatsumuriユーザーからの入力を受け付ける

ここではユーザーから名前と生年月日を入力してもらい、その結果を表示するアプリケーションを作ります。

leaf入力のしくみ

入力方法はHTMLのフォームと同じで、送信ボタンを押すとサーバーに送られます。サーバーにはマネージドビーンという送信データを受けとる簡単なJavaのクラス(POJO:Plain Old Java Object)を用意しておきます。JSFの仕組みによって送信された情報はマネージドビーンのプロパティに自動的にセットされます。そのあとは、JSFページでこれらプロパティを読み取り表示します。

JSFを使わない場合、サーブレットを作って送信されたデータを受け取りますが、その部分ががとても簡単になるというわけです。

leafマネージドビーンをつくる

マネージドビーンはJavaビーンズのようなものですが、要するにシンプルなJavaクラスです。マネージドビーンはJSFの仕組みによってインスタンス化やメソッドの呼び出しが自動的に行われるため「マネージド」(管理されている)という名前がついているのです。

作り方について説明します。

すべてのJavaクラスはパッケージの中に入れるべきです。NetBeansのプロジェクトウインドウでMyFirstプロジェクトの中のソースパッケージのところで右クリックして「新規パッケージ」を実行して続くウィザードでパッケージ名を設定します。ここでは「com.myjsf」としましょう。

21package-b

22package2

次にcom.myjsfパッケージのところで右クリックして[新規]-[JSF管理対象ビーン]を実行します。

23bean1

まずマネージドビーンの名前を決めます。Javaクラスなので最初は大文字で、UserInfoBeanとしましょうか。スコープの指定がありますがセッションを選びます。次のひな形のコードが自動的に作られます。これを編集してあなたのビーンを作るのです。

package com.myjsf;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
@Named(value = “userInfoBean”)
@SessionScoped
public class UserInfoBean implements Serializable {
public UserInfoBean() {
}
}

この中で@NamedはJNDI(Java Naming and Directory Interface)とよばれるJavaのネームサービスをもとにできているものです。JNDIはオブジェクトを名前で区別して検索したり教えてくれる機能です。

Namedアノーテーションは、このビーンズを参照するときの名前でクラス名の先頭が小文字になったものをデフォルトとしてセットしてくれます。別の名前に変えても構いません。SessionScopedアノーテーションはこのビーンズの生存期間がセッションであるということ。

次にユーザーから受けとりたい情報と形式を決めましょう。これはビーンの中でプロパティを用意するということです。名前を受け取りたいのでuserNameというプロパティを用意することにします。形式はString型がよいですね。

生年月日はbirthDayとします。これは1995/10/2とか1995.10.02とか色々な入力が想定されます。とりあえずどれにも対応できようString型にしておきます。後でよい方法を教えます。

・・・
public class UserInfoBean implements Serializable {
String userName;
String birthDay;
public UserInfoBean() {
・・・

マネージドビーンの規則として原則としてプロパティに値をセットするためのメソッド、セッターといいますがそれを用意しなければなりません。同じく値を読み出すためのメソッド、ゲッターを用意しなければなりません。それらの名前の付け方が決まっていて、userNameプロパティ用ならばsetUserName()、getUserName()とします。プロパティ名の先頭を大文字にしてその前にsetやgetを付けます。これは絶対まもらなければならないルールです。JSFのシステムはプロパティ名だけが分かれば、そのアクセスメソッド名は必ずわかるという仕組みになっています。

セッターとゲッターは私たちがコツコツと打ち込んで作ることもできるのですが、そんな単純な作業はお任せくださいとも言うようにNetBeansでは便利な方法が用意されています。

コードの中でセッターとゲッターを挿入したい場所にカーソルを置いて右クリックしてコンテキストメニューから「コード挿入」を選びます。次に「取得メソッドおよび設定メソッド」を選ぶと、どのプロパティに対してメソッドを作るか聞かれるので全部を選びます。最上位のチェックマークを選ぶとすべてのものが選ばれます。

24ins-code1

25ins-code2

これが完了するとコードが自動的に挿入されます。

26ins-code3

完成したマネージドビーンのコードは次のとおり完璧です。NetBeansを使うと生産性は格段に向上します。

package com.myjsf;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;

@Named(value = “userInfoBean”)
@SessionScoped
public class UserInfoBean implements Serializable {

String userName;
String birthDay;

public UserInfoBean() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getBirthDay() {
return birthDay;
}
public void setBirthDay(String birthDay) {
this.birthDay = birthDay;
}

JSFのマネージドビーンは、これまでJavaEE6以前では@ManagedBeanというアノーテーションを使っていましたが、今後は@Namedを使っていくようになります。最新のNetBeansでは「@ManagedBeanは推奨されません」と表示されます。現在はコンパティビリティのために正常に動作しますが将来は使用できなくなる可能性があります。次の2つのビーンのコードを見てください。ゴシックのところが違います。

[従来のマネージドビーンの記述]・・・今後推奨されない

package com.myjsf;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class UserInfoBean implements Serializable{

・・・・

[これからのマネージドビーンの記述]・・・推奨

package com.myjsf;
import java.io.Serializable;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named(value = “userInfoBean”)
@SessionScoped
public class UserInfoBean implements Serializable {

 

後者のコードはCDI(Contexts and Dependency Injection)タイプのマネージドビーンと呼ばれていています。CDIは Java EE 6から追加された(Dependency Injection、依存性注入)のための仕様で、Java EE 7におけるCDIのバージョンは1.1で、Java EE 7から CDIはデフォルトで有効化されています。今後はこのCDIを使った方式を推奨していくようですので、上記の後者のコードを使っていくとよいと思います。

leafJSFページをつくる

JSFページはユーザーからの入力を受け付けてマネージドビーンに格納することが簡単にできます。NetBeansで[新規ファイル]でregisterという名前のJSFページを作ります。

HTMLと同様にh:formタグを使います。そのなかにh:inputTextタグを書きます。これはHTMLのinput type=”text”と同じ意味です。

h:inputTextのvalue属性の書き方がJSFの最大のメリットです。マネージドビーン名とプロパティ名をドットで結んでかっこでくくって#をつけます。このときマネージドビーン名は”デフォルト”ではマネージドビーンのクラス名の先頭1文字を小文字にしたものにします。

value=”#{マネージドビーン名.プロパティ名}”

このようにするだけでユーザーがフォームを送信すると、JSFによってその値が自動的にマネージドビーンのプロパティにセットされるのです。プログラマーは入力機能の部分を書かなくてもよいのです。

NetBeansでは次の画面のようにマネージドビーン名を入力してピリオドを打つと、そこに登録されているプロパティを自動的に表示してくれますので選ぶだけで間違いもなく早くコードが書けます。h:inputタグのidは空のままなので何か記入します。

27code-auto-ins

送信ボタンはh:commandButtonで作ります。このままだとサーバーに送信した名前と生年月日が本当に届いているか確認できませんからh:outputTextタグを使って送信した値をページ内に表示しましょう。valueプロパティはh:inputTextタグと同様です。f:viewというタグがありますが、これはJSF関係のタグを含めるための入れもの的なものです。最終的には次のようなコードになります。

<?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”>
<f:view>
<h:head>
<title>User Registration</title>
</h:head>
<h:body>
<h:form>
お名前<h:inputText value=”#{userInfoBean.userName}”/><p/>
生年月日<h:inputText value=”#{userInfoBean.birthDay}”/><p/>
<h:commandButton type=”submit” value=”送信” />
<h:commandButton type=”reset” value=”キャンセル” /><p/>
</h:form>
<h:outputText value=”#{userInfoBean.userName}”/><p/>
<h:outputText value=”#{userInfoBean.birthDay}”/>
</h:body>
</f:view>
</html>

leaf実行する

プロジェクトウィンドウのregister.xhtmlファイルで右クリックして[ファイルの実行] を選びます。

28runブラウザーが自動的に立ち上がって入力ページが表示されますので、何か適当に入れます。

28run2

送信ボタンを押します。送信とキャンセルボタンの下に入力した情報がそのまま表示されることになっていますが、漢字が変なふうに化けてしまいました。

29error

ブラウザーの戻るボタンを押して、入力欄に正常な漢字になっていることを確認したうえでもう一度送信ボタンを押します。今度は正常に表示されました。

28run3

これは調べてみるとJSF2.xのバグの模様でリクエストのパラメータのエンコーディングが最初はうまく機能せず文字化けして2回目以降はずっと正常になるという現象です。

leaf文字化け対策

今後のバージョンアップでは改善すると思いますが、ネット上の情報では対策としてglassfish-web.xmlあるいはsun-web.xmlに次のように文字コードのエンコーディング指定をすればよいとのアドバイスありますがうまくいかないようです。

<parameter-encoding default-charset=”UTF-8″ />

ここでは確実な方法としてフィルターを利用します。

30filter1

ソースパッケージにEncodingFilter.javaを作ります。そして次のようなコードを書きます。これはweb.xmlに書いた「encoding」パラメータを読み取ってリクエストに対してsetCharacterEncodingメソッドでエンコーディング設定を行うフィルターです。

package com.myjsf;
import java.io.*;
import javax.servlet.*;

public class EncodingFilter implements Filter {
private String encoding;

@Override
public void init(FilterConfig config) throws ServletException {
encoding = config.getInitParameter(“encoding”);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
@Override
public void destroy() {}
}

NetBeansのプロジェクトウインドウでWEB-INFの下にあるweb.xmlをダブルクリックで開いて次の太字の部分を追記します。servlet-mappingタグが終わったあたりがいいと思います。

30filter2

・・・・

</servlet-mapping>
<filter>
<filter-name>Encoding</filter-name>
<filter-class>com.myjsf.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.xmlの設定はurl-patternタグですべてのurlに対してEncodingという名前のフィルターを必ず通すように指定しています。Encodingはfilter-nameタグで定義されていて、さっき作ったcom.myjsf.EncodingFilterであることが明示されています。これが実行されるのです。param-nameタグでencodingはutf-8とセットされていますから、必ずエンコーディングはUTF-8になります。

leafふたたび実行

実行すると次のようにページが表示されます。

31rerun1

何か入力して送信ボタンを押します。

31rerun2

今度は最初から文字化けせずに正常に表示されました。

31rerun3

leafまとめ

  • ユーザー入力はJSFのh:inputTextタグなどで受け付ける
  • 入力情報の出力はJSFのh:outputTextタグなどを使う
  • ユーザー入力情報はJSFによってマネージドビーンのプロパティに自動的にセットされる
  • マネージドビーンはJSFが自動的に管理してくれるのでインスタンス化などプログラマが行う必要はない。任せる。

バグがあったりして、ちょっと長くなってしましたが、今回はここまでです。

previousnext

JSF2.2のすべてをまとめたkindle電子書籍 「JavaServer Faces2.2 入門」もぜひご覧ください。パソコン、iPhone、Androidどんな端末用にもamazonが無料のKindle電子書籍リーダーを用意しています。それをつかってKindle本を手軽にお楽しみください。あなたが今お使いの端末用Kidle電子書籍リーダーのご案内

同書籍のPDF版は私自身が運営するこちらのサイトから直接購入できます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA