JSF2.2入門 第16回CDIとManagedBeanのRequestScoped(リクエストスコープ)


16title

CDIとManagedBeanの両方に共通するRequestScopedについて説明します。私の環境はNetBeansIDE8.1, JavaEE7, JSF2.2, GlassFish4.1.1, jdk1.8.0, jre1.8.0, 2016.10.5時点での情報です。NetBeansで新規プロジェクトを作成するときにフレームワークとしてJSF2.2(サーバー・ライブラリ)を指定しています。これが違うと挙動が異なる可能性がありますのでご注意ください。

katatsumuri-e1463911702620CDIのRequestScoped

leaf-e1463911721194CDIのJavaBeansの書き方

次のHobbyRequestBeanはユーザーに趣味を聞いてそれを格納するための単純なJavaBeansです。プロパティはたったひとつhobby(趣味)です。Namedアノーテーションはビーンを参照するためのもので、valueプロパティは指定した場合にはその値で参照することができます。省略した場合にはクラス名の先頭の文字を小文字にしたもので参照できます。これはルールです。

肝心のRequestScopeですが、次のように@javax.enterprise.context.RequestScopedと完全修飾子で指定します。その代わりjavax.enterprise.context.RequestScopedをインポート指定する必要はありません。これを単純に@RequestScopedとしてしまうとエラーになることがあります(上記の私の環境では必ずエラーになります)。

package com.myjsf;
import javax.inject.Named;
@Named(value=”hobbyRequestBean”)
@javax.enterprise.context.RequestScoped
public class HobbyRequestBean {
private String hobby;
public HobbyRequestBean() {
}

public String getHobby() {
return hobby;
}

public void setHobby(String hobby) {
this.hobby = hobby;
}
}

完全修飾子ではなく単純に@RequestScopedを使いたい場合には次のようにjavax.enterprise.context.RequestScopedをインポートして@RequestScopedを指定すればOKなはずですが、実際にはこれがうまくいかない場合があります。

たぶん、ManagedBeanでも@RequestScopedは同じアノーテーション名で使われますので、それとの区別がうまくいかないのだと思います。NetBeans, GlassFishのある種のバグではないかと思います。ManagedBeanのRequestScopedはjavax.faces.bean.RequestScopedで定義されていますのでパッケージが全く違うのです。

[CDIでうまくいかない例]
package com.myjsf;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named(value=”incorrectHobbyRequestBean”)
@RequestScoped
public class IncorrectHobbyRequestBean {....

のエラーは次のとおりで、「リクエストスコープのJavaBeansを使うためのコンテキストがアクティブになっていない」というエラーです。WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped

20161104-1

leaf-e1463911721194CDIのJavaBeansの使い方

使い方について説明します。使い方はCDIでもManagedBeansでも同じです。このJSFページは趣味を入力してもらい、コマンドボタンを押すと入力値を表示するものです。ちょっと変わっているのはコマンドボタンが3つあることです。1つ目のボタンを押すと同じページ内で結果が表示されるものです。2つ目のボタンはscopeCheckNextPage.xhtmlという別のページにforwardして表示する例です。3つ目は同じscopeCheckNextPage.xhtmlで表示するものの、redirectを使って転送するものです。

[入力画面requestScopeSample.xhtml]

<?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”>
<h:head>
<title>RequestScope sample</title>
</h:head>
<h:body>
<h2>RequestScopeの例</h2>
<h:form>
あなたの趣味は何ですか:<h:inputText value=”#{hobbyRequestBean.hobby}”/><p/>
<h:commandButton value=”このページで表示” /><p/>
<h:commandButton value=”Forwardして表示” action=”scopeCheckNextPage.xhtml”/><p/>
<h:commandButton value=”Redirectして表示” action=”scopeCheckNextPage.xhtml?faces-redirect=true;“/>
</h:form>
<br/>
あなたが入力した趣味:
<h:outputText value=”#{hobbyRequestBean.hobby}”/>
</h:body>
</html>

leaf-e1463911721194実行してみる

まず入力画面に「旅行」と入れる。

20161104-2

これら3つのボタンを押した結果は次のようになります。

[同じページで表示]・・・OK。 JavaBeansの情報が保持され読み出すことができる。

20161104-3

[Forwardで表示]・・・OK。これもJavaBeansが有効に機能している。

20161104-4

[Redirectで表示]・・・NG。JavaBeansが無効でhobbyプロパティが見つからない、つまりJavaBeansがスコープ外になっている。

20161104-5

leaf-e1463911721194有効範囲のまとめ

まとめると、CDIでRequestScopedにした場合、JavaBeansの有効無効は次のようになります。Forwardで別のページに転送された場合でも、転送元と転送先は1つのHTTPリクエスト・レスポンスの範囲内とみなされているからです。それに対してRedirectは2回のリクエストとみなされます。これはManagedBeanでRequestScopedにした場合でも同じです。

同じページで表示
Forwardで表示
Redirectで表示 ×

katatsumuri-e1463911702620ManagedBeanのRequestScoped

leaf-e1463911721194ManagedBeanでのRequestScopeの指定のしかた

さきほどと全く同じ機能のJavaBeansをManagedBeanで作ります。CDIと違うところは赤文字のところです。インポートするパッケージが違います。また@RequestScopedは完全修飾子で指定しなくても、ごく普通に書けば問題なく動きます。クラス名はさきほどと変えています。

package com.myjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class HobbyRequestManagedBean {
private String hobby;
public HobbyRequestManagedBean() {
}

public String getHobby() {
return hobby;
}

public void setHobby(String hobby) {
this.hobby = hobby;
}
}

leaf-e1463911721194ManagedBeanの使い方

JSFページにおける使い方はさきほどのCDIとまったく同じです。

[requestScopeSampleMB.xhtml]

<?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”>
<h:head>
<title>RequestScope sample</title>
</h:head>
<h:body>
<h2>RequestScopeの例</h2>
<h:form>
あなたの趣味は何ですか:<h:inputText value=”#{hobbyRequestManagedBean.hobby}”/><p/>
<h:commandButton value=”このページで表示” /><p/>
<h:commandButton value=”Forwardして表示” action=”scopeCheckNextPageMG.xhtml”/><p/>
<h:commandButton value=”Redirectして表示” action=”scopeCheckNextPageMG.xhtml?faces-redirect=true;”/>
</h:form>
<br/>
あなたが入力した趣味:
<h:outputText value=”#{hobbyRequestManagedBean.hobby}”/>
</h:body>
</html>

leaf-e1463911721194実行結果

結果はCDIの場合と同じで、同一ページ内での表示はOK、ForwardはOK、RedirectはNGです。

[同一ページでの表示結果]・・・OK

20161104-7

[Forwardで表示]・・・OK

20161104-8

[Redirectで表示]・・・NG

20161104-9

以上です。

previousnext

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