JSFでは、value
属性とbinding
属性を区別する多くの資料があります。
両方のアプローチが互いにどのように異なるかに興味があります。与えられた:
public class User {
private String name;
private UICommand link;
// Getters and setters omitted.
}
<h:form>
<h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>
value
属性が指定されたときに何が起こるかは非常に簡単です。ゲッターが実行され、name
BeanのUser
プロパティ値が返されます。値はHTML出力に出力されます。
しかし、binding
がどのように機能するのか理解できませんでした。生成されたHTMLは、link
BeanのUser
プロパティとのバインディングをどのように維持しますか?
以下は、手作業による美化とコメント化後に生成された出力の関連部分です(id j_id_jsp_1847466274_1
は自動生成され、2つの非表示入力ウィジェットがあることに注意してください)。 SunのJSF RIバージョン1.2を使用しています。
<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
id="j_id_jsp_1847466274_1" method="post" name="j_id_jsp_1847466274_1">
<input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
<a href="#" onclick="...">Name</a>
<input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
type="hidden" value="-908991273579182886:-7278326187282654551">
</form>
binding
はどこに保存されていますか?
JSFビュー(Facelets/JSPファイル)が構築/復元されると、JSFコンポーネントツリーが作成されます。その瞬間、 ビュー構築時間 、すべてのbinding
属性が評価されます( id
属性とJSTLのようなタグハンドラー )。コンポーネントツリーに追加する前にJSFコンポーネントを作成する必要がある場合、JSFはbinding
属性が事前に作成されたコンポーネント(つまり、_null
以外)を返すかどうかを確認し、返す場合はそれを使用します。事前に作成されていない場合、JSFはコンポーネントを「通常の方法」で自動作成し、自動作成されたコンポーネントインスタンスを引数としてbinding
属性の背後にあるセッターを呼び出します。
効果では、コンポーネントツリーのコンポーネントインスタンスの参照をスコープ変数にバインドします。この情報は、コンポーネント自体の生成されたHTML表現には決して表示されません。とにかく、この情報は、生成されたHTML出力に関連するものではありません。フォームが送信され、ビューが復元されると、JSFコンポーネントツリーが最初から再構築され、すべてのbinding
属性が上の段落で説明したように再評価されます。コンポーネントツリーが再作成された後、JSFはJSFビューステートをコンポーネントツリーに復元します。
知っておくべき重要なことは、具象コンポーネントのインスタンスが効果的にリクエストスコープされていることです。これらはすべてのリクエストで新しく作成され、それらのプロパティには、ビューの復元段階でJSFビューステートからの値が入力されます。そのため、コンポーネントをバッキングBeanのプロパティにバインドする場合、バッキングBeanはabsolutely notリクエストスコープよりも広いスコープ内にある必要があります。 JSF 2.0仕様 3.1.5章も参照してください。
3.1.5コンポーネントのバインド
...
コンポーネントバインディングは、マネージドBean作成機能を介して動的にインスタンス化されるJavaBeansと組み合わせて使用されることがよくあります(セクション5.8.1「VariableResolverとデフォルトVariableResolver」を参照)。 アプリケーション開発者は、コンポーネントバインド式が指すマネージドBeanを「要求」スコープに配置することを強くお勧めします。これは、UIComponentインスタンスがセッションまたはアプリケーションスコープに配置されると、スレッドセーフが必要になるためですシングルスレッド内で実行することに依存します。また、コンポーネントバインディングを「セッション」スコープに配置すると、メモリ管理に悪影響を与える可能性があります。
そうでない場合、コンポーネントインスタンスは複数のリクエスト間で共有され、ビューで宣言されたバリデーター、コンバーター、リスナーが既存のコンポーネントインスタンスに再アタッチされるため、「 duplicate component ID 」エラーと「奇妙な」動作が発生する可能性があります前のリクエストから。症状は明らかです。複数回実行され、コンポーネントがバインドされているのと同じスコープ内の各リクエストでさらに1回実行されます。
また、負荷が高い場合(つまり、複数の異なるHTTPリクエスト(スレッド)が同じコンポーネントインスタンスに同時にアクセスして操作する場合)、遅かれ早かれ、たとえば IComponent.popComponentFromELでスタックスレッド 、または richfaces UIDataAdaptorBaseとその内部HashMapを使用したCPU使用率100%のJavaスレッド 、または「奇妙な」IndexOutOfBoundsException
またはConcurrentModificationException
JSFがビューステートの保存または復元に忙しい間、JSF実装ソースコードから直接来ます(つまり、スタックトレースはsaveState()
またはrestoreState()
メソッドなどを示します)。
binding
を使用するのは悪い習慣ですとにかく、この方法でbinding
を使用すると、要求スコープBeanでさえ、コンポーネントインスタンス全体をBeanプロパティにバインドすることは、JSF 2.xではかなりまれなユースケースであり、一般的にベストプラクティスではありません。デザインの匂いを示しています。通常、ビュー側でコンポーネントを宣言し、value
などのランタイム属性、およびおそらくstyleClass
、disabled
、rendered
などのその他のランタイム属性を通常のBeanプロパティにバインドします。次に、コンポーネント全体を取得して属性に関連付けられたセッターメソッドを呼び出す代わりに、必要なBeanプロパティを正確に操作します。
コンポーネントを静的モデルに基づいて「動的に構築」する必要がある場合、 JSTLなどの構築時タグを表示 を使用することをお勧めします。必要に応じて タグファイルcreateComponent()
、new SomeComponent()
、getChildren().add()
の代わりに。 古いJSPのスニペットをJSFの同等のものにリファクタリングする方法 も参照してください。
または、動的モデルに基づいてコンポーネントを「動的にレンダリング」する必要がある場合は、単に イテレータコンポーネント (<ui:repeat>
、<h:dataTable>
など)を使用します。 JSFコンポーネントを動的に追加する方法 も参照してください。
複合コンポーネントはまったく別の話です。 <cc:implementation>
内のコンポーネントをバッキングコンポーネント(<cc:interface componentType>
で識別されるコンポーネント)にバインドすることは完全に合法です。ao 時間を表す2つのh:inputTextフィールドにまたがるJava.util.Dateの分割f:convertDateTimeで分 および JSF 2.0複合コンポーネントで動的リストを実装する方法?
binding
を使用しますただし、アクション/値に依存する検証に関連するユースケースでは、特定のコンポーネントの内部とは異なるコンポーネントの状態について頻繁に知りたい場合があります。そのためには、binding
属性を使用できますが、Beanプロパティと組み合わせてnotを使用できます。 binding="#{foo}"
のようにbinding
属性でローカルELスコープの一意の変数名を指定するだけで、コンポーネントはUIComponent
参照として同じビューの他の場所でレンダリング応答中に直接使用できます。 #{foo}
。そのようなソリューションが答えに使用されているいくつかの関連する質問があります:
EL式を使用して、コンポーネントIDをJSFの複合コンポーネントに渡します
(それは先月からのものです...)
各JSFコンポーネントはそれ自体をHTMLにレンダリングし、生成するHTMLを完全に制御します。 JSFで使用できるトリックは多数あり、どのトリックを使用するかは、使用しているJSF実装によって異なります。
Hlinkのようなものについては、クエリパラメータとして、またはURL自体の一部として、またはmatrxパラメータとして、URLにバインド情報を含めることができます。たとえば。
http:..../somelink?componentId=123
は、jsfがコンポーネントツリーを見て、リンク123がクリックされたことを確認できるようにします。またはhtp:..../jsf;LinkId=123
この質問に答える最も簡単な方法は、リンクが1つだけのJSFページを作成し、それが生成するHTML出力を調べることです。そうすれば、使用しているJSFのバージョンを使用して、これがどのように起こるかを正確に知ることができます。