回答:
JSTL <c:xxx>
タグはすべてタグハンドラであり、ビューのビルド時に実行され<h:xxx>
ますが、JSF タグはすべてUIコンポーネントであり、ビューのレンダリング時に実行されます。
JSF自身からという注意<f:xxx>
と<ui:xxx>
タグだけないものではないから延びるが、UIComponent
またtaghandlersあり、例えば<f:validator>
、<ui:include>
、<ui:define>
、などから延びているものUIComponent
もJSFのUIコンポーネントであり、例えば<f:param>
、<ui:fragment>
、<ui:repeat>
JSF UIコンポーネントから、などのみid
とbinding
属性でありますビューのビルド時にも評価されます。したがって、JSTLライフサイクルに関する以下の回答は、JSFコンポーネントの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>
...ビューのビルド時<h:outputText>
に、JSFコンポーネントツリーに3つの個別のコンポーネントを作成します。大まかに次のように表されます。
<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コンポーネントであるを使用して3つの項目を繰り返し処理しますが、
<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}
、ビューのレンダリング時にのみ使用できるため、このように子コンポーネントの属性でELを使用することもできません。同じことがh:dataTable
類似のコンポーネントにも当てはまります。
<c:if>
/ <c:choose>
vsrendered
別の例として、この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>
... コンポーネントをJSFコンポーネントツリーにtype = TEXT
追加するだけの場合<h:inputText>
:
<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コンポーネントツリーでは上記とまったく同じになります。したがって、これらのコンポーネントツリーが多数あり、それらが実際に「静的」モデルに基づいている場合(つまり、field
少なくともビュースコープの間は変更されない)、これは「肥大化した」コンポーネントツリーになる可能性があります。また、2.2.7より前のバージョンのMojarraで追加のプロパティを持つサブクラスを処理すると、ELの問題が発生する可能性があります。
<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
、許容値のいずれかを持つ属性をrequest
、view
、session
、またはapplication
、それはビューのビルド時に、すぐに評価され、指定されたスコープに保存されます。
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
これは一度だけ評価さ#{dev}
れ、アプリケーション全体を通して利用できます。
JSTLを使用して予期しない結果が生じるの<h:dataTable>
は<ui:repeat>
、などのJSF反復コンポーネント内で使用した場合、またはJSTLタグ属性が次のようなJSFイベントの結果に依存している場合のみです。preRenderView
、またはビューの構築時に利用できないモデルで送信されたフォーム値。そのため、JSTLコンポーネントツリー構築のフローを制御するためにのみJSTLタグを使用します。JSF UIコンポーネントを使用して、HTML出力生成のフローを制御します。var
反復するJSFコンポーネントをJSTLタグ属性にバインドしないでください。JSTLタグ属性のJSFイベントに依存しないでください。
コンポーネントをを介してバッキングBeanにバインドするbinding
か、を介してコンポーネントを取得findComponent()
し、バッキングBeanでJavaコードを使用してその子を作成/操作する必要があると思うときはいつでもnew SomeComponent()
する必要があると思われる場合は、すぐに停止し、代わりにJSTLの使用を検討してください。JSTLもXMLベースであるため、JSFコンポーネントを動的に作成するために必要なコードは、非常に読みやすく、保守しやすくなります。
知っておくべき重要なことは、2.1.18より前のバージョンのMojarraには、JSTLタグ属性でビュースコープBeanを参照するときに部分的な状態の保存に関するバグがあったことです。ビュースコープBean全体が、ビューツリーから取得されるのではなく、新しく再作成されます(JSTLの実行時点では、ビューツリー全体がまだ利用できないためです)。JSTLタグ属性によってビュースコープBeanの状態を予測または格納している場合、期待した値が返されないか、ビューの後で復元される実際のビュースコープBeanで「失われる」ツリーが構築されます。Mojarra 2.1.18以降にアップグレードできない場合の回避策はweb.xml
、以下のように部分的な状態の保存をオフにすることです。
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
@ViewScoped
タグハンドラーでの失敗JSTLタグが役立つ実際の例をいくつか見るには(つまり、ビューの構築中に実際に適切に使用した場合)、次の質問/回答を参照してください。
あなたがしたい場合は、あなたの具体的な機能要件については、レンダリング条件付き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>
<ui:repeat>
(「なぜならこのラインの、タグハンドラをあるJSF自身のそのノート<f:xxx>
と<ui:xxx>
...ちょうどのような」) <c:forEach>
、したがって、それはで評価されたビューの構築時間(再びただ単になどのような<c:forEach>
) 。その場合、との間に目に見える機能的な違いは<ui:repeat>
あり<c:forEach>
ませんか?私はその段落が正確に何を意味するのか理解できません:)
<f:xxx>
して<ui:xxx>
は延びていないタグUIComponent
、タグハンドラです。」それが意味するものではしようとする試み<ui:repeat>
もあるため、タグハンドラで<ui:xxx>
も含まれるの<ui:repeat>
?これは、それが拡張の<ui:repeat>
コンポーネントの1つであることを意味<ui:xxx>
しますUIComponent
。したがって、それはタグハンドラではありません。(それらの一部は拡張されない場合がありますUIComponent
。したがって、それらはタグハンドラです)
<c:set>
をscope
作成しません。scope="request"
代わりに試してください。これは、値をすぐに評価し(実際にビューのビルド時に)、それを要求属性として設定します(反復中に「上書き」されません)。カバーの下で、ValueExpression
オブジェクトを作成および設定します。
ClassNotFoundException
。プロジェクトの実行時の依存関係が壊れています。Tomcatなどの非JavaEEサーバーを使用していて、JSTLをインストールするのを忘れた、またはJSTL 1.0とJSTL 1.1+の両方を誤って含めた可能性があります。JSTL 1.0ではパッケージがjavax.servlet.jstl.core.*
あり、JSTL 1.1以降はこれになっていjavax.servlet.jsp.jstl.core.*
ます。JSTLをインストールするための手がかりはここにあります:stackoverflow.com/a/4928309
使用する
<h:panelGroup rendered="#{lpc.verbose}">
...
</h:panelGroup>
スイッチのような出力の場合、PrimeFaces Extensionsのスイッチフェイスを使用できます。