[解決済み] JSF2 FaceletsでJSTL...意味があるのか?
質問
Faceletsのコードを少し条件付きで出力したいのですが。
そのためには、JSTLタグで問題ないようです。
<c:if test="${lpc.verbose}">
...
</c:if>
しかし、「これはベストプラクティスなのか? 私の目標を達成するための他の方法はないのでしょうか?
どのように解決するのですか?
はじめに
JSTL
<c:xxx>
タグはすべて
タグハンドラ
の間に実行されます。
ビュー構築時
一方、JSFは
<h:xxx>
タグはすべて
UIコンポーネント
の間に実行されます。
ビューレンダリングタイム
.
なお、JSF自身の
<f:xxx>
と
<ui:xxx>
を行うもののみです。
ではなく
からの拡張
UIComponent
はタグハンドラでもあり、例えば
<f:validator>
,
<ui:include>
,
<ui:define>
など。から伸びるものは
UIComponent
はJSFのUIコンポーネントでもあり、例えば
<f:param>
,
<ui:fragment>
,
<ui:repeat>
など。JSFのUIコンポーネントからは
id
と
binding
属性は、ビューの構築時にも評価されます。したがって、JSTLライフサイクルに関する以下の回答は、ビューの構築時に評価される
id
と
binding
属性を使用します。
ビュー構築時とは、XHTML/JSPファイルを解析してJSFコンポーネントツリーに変換し、それを
UIViewRoot
の
FacesContext
. ビューレンダータイムとは、JSFコンポーネントツリーがHTMLを生成しようとする瞬間のことで、その始まりは
UIViewRoot#encodeAll()
. だから JSF UI コンポーネントと JSTL タグは、コーディングから予想されるように同期して実行されません。次のように可視化することができます。まず JSTL が上から下に向かって実行され、JSF コンポーネントツリーが生成されます。そして、JSF が再び上から下に向かって実行され、HTML 出力が生成される番です。
<c:forEach>
対
<ui:repeat>
例えば、このFaceletsマークアップは、3つの項目を反復するために
<c:forEach>
:
<c:forEach items="#{bean.items}" var="item">
<h:outputText id="item_#{item.id}" value="#{item.value}" />
</c:forEach>
...ビューのビルド時に、3つの別々の
<h:outputText>
コンポーネントは、JSFのコンポーネントツリーで、おおよそこのように表現されます。
<h:outputText id="item_1" value="#{bean.items[0].value}" />
<h:outputText id="item_2" value="#{bean.items[1].value}" />
<h:outputText id="item_3" value="#{bean.items[2].value}" />
...そして、ビューのレンダリング時に個別にHTML出力を生成します。
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
コンポーネント ID の一意性を手動で確認する必要があることと、ビューのビルド時にそれらも評価されることに注意してください。
このFaceletsマークアップでは
<ui:repeat>
これはJSFのUIコンポーネントです。
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
...すでにJSFのコンポーネントツリーでそのまま終了しており、そこでまったく同じ
<h:outputText>
コンポーネントは、ビューレンダリング時に
再利用
を使用して、現在の反復ラウンドに基づく HTML 出力を生成します。
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
ただし
<ui:repeat>
であることから
NamingContainer
コンポーネントは、すでに反復インデックスに基づくクライアントIDの一意性を確保しています。また、ELを
id
属性もビューの構築時に評価されるため、この方法で子コンポーネントの
#{item}
は、ビューレンダリング時にのみ利用可能です。同じことが
h:dataTable
と同様の構成要素です。
<c:if>
/
<c:choose>
対
rendered
別の例として、この Facelets のマークアップでは、条件付きで異なるタグを
<c:if>
(を使用することもできます。
<c:choose><c:when><c:otherwise>
を使用します)。
<c:if test="#{field.type eq 'TEXT'}">
<h:inputText ... />
</c:if>
<c:if test="#{field.type eq 'PASSWORD'}">
<h:inputSecret ... />
</c:if>
<c:if test="#{field.type eq 'SELECTONE'}">
<h:selectOneMenu ... />
</c:if>
...の場合は
type = TEXT
を追加するだけです。
<h:inputText>
コンポーネントを JSF コンポーネントツリーに追加します。
<h:inputText ... />
このFaceletsのマークアップをしながら
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
...は、条件に関係なく、JSFのコンポーネントツリーで上記のように正確に終了します。このため、多くのコンポーネントがあり、それらが実際にはquot;static"モデルに基づいている場合、コンポーネントツリーがquot;bloated"になってしまうかもしれません(
field
は少なくともビュースコープの間は変更されません)。また、EL
トラブル
2.2.7より前のバージョンのMojarraで、追加のプロパティを持つサブクラスを扱うとき。
<c:set>
対
<ui:param>
両者は互換性がありません。その
<c:set>
はELスコープ内の変数を設定し、その変数にアクセスできるのは
の後に
タグの位置は、ビューの構築時に指定され、 ビューのレンダリング時にはビューの任意の場所に指定されます。また
<ui:param>
を介してインクルードされたFaceletテンプレートにEL変数を渡します。
<ui:include>
,
<ui:decorate template>
または
<ui:composition template>
. 古いバージョンのJSFでは
<ui:param>
変数が Facelet テンプレートの外側でも利用可能であるため、決してこれに頼ってはいけません。
その
<c:set>
を使用せずに
scope
属性はエイリアスのように振る舞います。これは、どのようなスコープにおいても、EL式の結果をキャッシュすることはありません。従って、例えばJSFコンポーネントを反復する内部で使用しても全く問題ありません。従って、例えば以下のように使用することができます。
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
ただ、ループの中で合計を計算する場合などには不向きです。そのような場合は、代わりに EL 3.0ストリーム :
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
だけ、設定すると
scope
属性に、許容される値のうちの1つを指定します。
request
,
view
,
session
または
application
を指定すると、ビューの構築時に直ちに評価され、指定したスコープに格納されます。
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
これは一度だけ評価され、次のように利用できます。
#{dev}
は、アプリケーション全体を通して
JSTL を使用して JSF コンポーネントのツリー構築を制御する
JSTLを使用すると、以下のようなJSF反復コンポーネント内部で使用した場合にのみ、予期せぬ結果を招く可能性があります。
<h:dataTable>
,
<ui:repeat>
など、JSTLタグの属性がJSFイベントの結果に依存する場合、または
preRenderView
または、ビューの構築時に利用できない、モデル内の送信されたフォームの値。ですから、JSTLタグは、JSFコンポーネントのツリー構築のフローを制御するためにのみ使用してください。JSF UI コンポーネントは、HTML 出力生成のフローを制御するために使用してください。をバインドしないでください。
var
を、JSTLタグの属性に反復して適用しています。JSTL タグの属性において、JSF イベントに依存しないこと。
バッキングビーンにコンポーネントをバインドする必要がある場合は、いつでも
binding
を使うか、あるいは
findComponent()
を持つバッキングビーンの中で、Java コードを使用してその子を作成/操作します。
new SomeComponent()
そのような場合は、すぐにJSTLの使用を中止して、代わりにJSTLを使用することを検討してください。JSTL は XML ベースなので、JSF コンポーネントを動的に作成するために必要なコードは、非常に読みやすく、保守しやすくなります。
重要なのは、Mojarraの2.1.18より古いバージョンでは、JSTLタグ属性でビュースコープされたビーンを参照する場合、部分的な状態保存のバグがあったということです。ビュースコープされたビーン全体は
新たに
は、ビューツリーから取得するのではなく、再作成されます (単に、JSTL が実行される時点では、完全なビューツリーがまだ利用可能でないためです)。もし、JSTLタグ属性によってビュースコープされたビーンに何らかの状態を期待したり保存したりしている場合、期待した値を返さなかったり、ビューツリーが構築された後に復元される実際のビュースコープされたビーンにおいて "lost"されたりすることがあります。Mojarra 2.1.18 以降にアップグレードできない場合は、以下の方法で部分的な状態保存をオフにすることができます。
web.xml
のようにします。
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
こちらもご覧ください。
- ビューの構築時間は?
- JSFの'binding'属性はどのように機能するのですか?いつ、どのように使うべきですか?
- 古いJSPのスニペットをJSFの同等品にリファクタリングする方法は?
- PARTIAL_STATE_SAVINGはfalseに設定すべきですか?
-
JSF2.0での通信
@ViewScoped
タグハンドラで失敗する
JSTLタグが役に立つ(つまり、ビューの構築時に本当に適切に使用される)実際の例を見るには、以下の質問/回答を参照してください。
- JSFコンポジットコンポーネントのグリッドを作るには?
- JSFでテーブルのカラムを動的に作成する
- カスタムレイアウト h:selectOneRadioの作り方
- JSFにおける条件付き変数定義
- h:selectOneRadio />に似た複合コンポーネントを作るには?
- JSF 2 -- f:ajaxにオプションのリスナー属性を持つコンポジットコンポーネント
- ネストされたJSFコンポジットコンポーネントによるStack Overflow例外の発生
ひとことで言うと
具体的な機能要件についてですが、仮に
レンダリング
JSFコンポーネントを条件付きで使用するには
rendered
属性の代わりに、JSF HTML コンポーネントの
特に
もし
#{lpc}
のようなJSFイテレートコンポーネントの現在イテレートされている項目を表します。
<h:dataTable>
または
<ui:repeat>
.
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
あるいは、もしあなたが
ビルド
(作成/追加) JSF コンポーネントを条件付きで使用する場合は、JSTL を使用し続けてください。それは、冗長に
new SomeComponent()
をjavaで実行します。
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
こちらもご覧ください。
関連
-
[解決済み] <f:facet>は何をするもので、どのような場合に使用するのですか?
-
[解決済み] 空またはNULLのJSTL cタグを評価する
-
[解決済み] javax.validation.ConstraintViolationException
-
[解決済み] p:dashboardが終了してもソート順を維持する。
-
[解決済み] ビーンスコープを正しく選ぶには?
-
[解決済み] commandButton/commandLink/ajax アクション/リスナーメソッドが呼び出されないか、入力値が設定/更新されない。
-
[解決済み】JSFリソースライブラリは何のためにあり、どのように使用すべきですか?
-
[解決済み】JSF 2.0 Faceletsを使用してXHTMLに別のXHTMLを含めるにはどうすればよいですか?
-
[解決済み] Java EE / JSF で j_security_check を使用してユーザー認証を行う。
-
[解決済み] divタグをレンダリングできるjsfコンポーネントは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] javax.faces.application.ViewExpiredException: ビューを復元できませんでした
-
[解決済み] JSF 2.2でターゲットが到達できない、識別子がヌルに解決される [重複] 。
-
[解決済み] java.lang.ClassNotFoundException: javax.faces.webapp.FacesServlet
-
[解決済み] javax.validation.ConstraintViolationException
-
[解決済み】JSFリソースライブラリは何のためにあり、どのように使用すべきですか?
-
[解決済み】PrimeFacesのprocess/updateとJSFのf:ajax execute/renderの属性を理解する。
-
[解決済み] JSF2 FaceletsでJSTL...意味があるのか?
-
[解決済み] Java EE / JSF で j_security_check を使用してユーザー認証を行う。
-
[解決済み] <f:metadata>、<f:viewParam>、<f:viewAction>は何に使えるのでしょうか?
-
[解決済み] javax.el.PropertyNotFoundException の識別と解決。ターゲットに到達できない