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
도 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>
vs <ui:repeat>
예를 들어이 Facelets 마크 업은 <c:forEach>
다음을 사용하여 3 개 이상의 항목을 반복합니다 .
<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 컴포넌트 트리에서 그대로 종료되며, 현재의 반복 라운드를 기반으로 HTML 출력을 생성하기 위해 <h:outputText>
뷰 렌더 시간이 재사용 되는 동안 매우 동일한 컴포넌트가 사용 됩니다.
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
참고 그 <ui:repeat>
있는 Being 같은 NamingContainer
성분이 이미 반복 인덱스에 기초하여 상기 클라이언트 ID의 고유성을 보장; 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'}" />
...will end up exactly as above in the JSF component tree regardless of the condition. This may thus end up in a "bloated" component tree when you have many of them and they are actually based on a "static" model (i.e. the field
does not ever change during at least the view scope). Also, you may run into EL trouble when you deal with subclasses with additional properties in Mojarra versions before 2.2.7.
<c:set>
vs <ui:param>
They are not interchangeable. The <c:set>
sets a variable in the EL scope, which is accessible only after the tag location during view build time, but anywhere in the view during view render time. The <ui:param>
passes an EL variable to a Facelet template included via <ui:include>
, <ui:decorate template>
, or <ui:composition template>
. Older JSF versions had bugs whereby the <ui:param>
variable is also available outside the Facelet template in question, this should never be relied upon.
The <c:set>
without a scope
attribute will behave like an alias. It does not cache the result of the EL expression in any scope. It can thus perfectly fine be used inside for example iterating JSF components. Thus, e.g. below will work fine:
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
It's only not suitable for e.g. calculating the sum in a loop. For that instead use EL 3.0 stream:
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
Only, when you set the scope
attribute with one of allowable values request
, view
, session
, or application
, then it will be evaluated immediately during view build time and stored in the specified scope.
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
This will be evaluated only once and available as #{dev}
throughout the entire application.
Use JSTL to control JSF component tree building
Using JSTL may only lead to unexpected results when being used inside JSF iterating components such as <h:dataTable>
, <ui:repeat>
, etc, or when JSTL tag attributes depend on results of JSF events such as preRenderView
or submitted form values in the model which aren't available during view build time. So, use JSTL tags only to control flow of JSF component tree building. Use JSF UI components to control flow of HTML output generation. Do not bind the var
of iterating JSF components to JSTL tag attributes. Do not rely on JSF events in JSTL tag attributes.
Anytime you think you need to bind a component to the backing bean via binding
, or grab one via findComponent()
, and create/manipulate its children using Java code in a backing bean with new SomeComponent()
and what not, then you should immediately stop and consider using JSTL instead. As JSTL is also XML based, the code needed to dynamically create JSF components will become so much better readable and maintainable.
Important to know is that Mojarra versions older than 2.1.18 had a bug in partial state saving when referencing a view scoped bean in a JSTL tag attribute. The whole view scoped bean would be newly recreated instead of retrieved from the view tree (simply because the complete view tree isn't available yet at the point JSTL runs). If you're expecting or storing some state in the view scoped bean by a JSTL tag attribute, then it won't return the value you expect, or it will be "lost" in the real view scoped bean which is restored after the view tree is built. In case you can't upgrade to Mojarra 2.1.18 or newer, the work around is to turn off partial state saving in web.xml
like below:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
See also:
- What's the view build time?
- How does the 'binding' attribute work in JSF? When and how should it be used?
- How to refactor snippet of old JSP to some JSF equivalent?
- Should PARTIAL_STATE_SAVING be set to false?
- Communication in JSF 2.0 -
@ViewScoped
fails in tag handlers
To see some real world examples where JSTL tags are helpful (i.e. when really properly used during building the view), see the following questions/answers:
- How to make a grid of JSF composite component?
- Create table columns dynamically in JSF
- How to custom layout h:selectOneRadio
- Conditional variable definition in JSF
- How to make composite component similar to <h:selectOneRadio />
- JSF 2 -- Composite component with optional listener attribute on f:ajax
- Nested JSF Composite Components leading to a Stack Overflow exception
In a nutshell
As to your concrete functional requirement, if you want to render JSF components conditionally, use the rendered
attribute on the JSF HTML component instead, particularly if #{lpc}
represents the currently iterated item of a JSF iterating component such as <h:dataTable>
or <ui:repeat>
.
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
Or, if you want to build (create/add) JSF components conditionally, then keep using JSTL. It's way much better than verbosely doing new SomeComponent()
in java.
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
See also:
- Conditionally displaying JSF components
- JSTL c:if doesn't work inside a JSF h:dataTable
- Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work
use
<h:panelGroup rendered="#{lpc.verbose}">
...
</h:panelGroup>
Sorry for the separate answer, but I couldn't comment answers above.
For switch-like output you can use switch from primefaces-extensions.
참고URL : https://stackoverflow.com/questions/3342984/jstl-in-jsf2-facelets-makes-sense
'IT story' 카테고리의 다른 글
배쉬 : 출력에서 후행 줄 바꿈 (0) | 2020.06.04 |
---|---|
사전을 선택하십시오 (0) | 2020.06.04 |
“Class.forName ()”과“Class.forName (). newInstance ()”의 차이점은 무엇입니까? (0) | 2020.06.04 |
요소 이름에 CSS 스타일을 적용 할 수 있습니까? (0) | 2020.06.04 |
Tmux에서 스크롤 백 버퍼를 지우려면 어떻게해야합니까? (0) | 2020.06.04 |