Jan*_*Jan 159 jsf jstl facelets jsf-2
我想有条件地输出一些Facelets代码.
为此,JSTL标签似乎工作正常:
<c:if test="${lpc.verbose}">
...
</c:if>
Run Code Online (Sandbox Code Playgroud)
但是,我不确定这是否是最佳做法?还有另一种方法来实现我的目标吗?
Bal*_*usC 313
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生命周期也适用于id
和binding
JSF组件的属性.
该视图生成时间是当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>
Run Code Online (Sandbox Code Playgroud)
...在视图构建期间创建<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}" />
Run Code Online (Sandbox Code Playgroud)
...在视图渲染时间内依次单独生成HTML输出:
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
Run Code Online (Sandbox Code Playgroud)
请注意,您需要手动确保组件ID的唯一性,并且还要在视图构建期间评估这些ID.
使用这个Facelets标记迭代3个项目<ui:repeat>
,这是一个JSF UI组件:
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
Run Code Online (Sandbox Code Playgroud)
...已经在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>
Run Code Online (Sandbox Code Playgroud)
注意,<ui:repeat>
作为NamingContainer
组件已经基于迭代索引确保了客户端ID的唯一性; 也不可能以id
这种方式在子组件的属性中使用EL,因为它也在视图构建期间进行评估,而#{item}
仅在视图渲染时间期间可用.对于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>
Run Code Online (Sandbox Code Playgroud)
... type = TEXT
仅在将<h:inputText>
组件添加到JSF组件树的情况下:
<h:inputText ... />
Run Code Online (Sandbox Code Playgroud)
虽然这个Facelets标记:
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
Run Code Online (Sandbox Code Playgroud)
...无论条件如何,都将在JSF组件树中完全如上所述.因此,当您拥有其中许多组件树时,这可能最终会出现在"膨胀"的组件树中,并且它们实际上基于"静态"模型(即field
,至少在视图范围内不会发生变化).此外,在2.2.7之前的Mojarra版本中处理具有其他属性的子类时,可能会遇到EL 问题.
<c:set>
VS <ui:param>
它们不可互换.该<c:set>
套在EL作用域的变量,只可以访问后在视图生成时的标签位置,但鉴于在视图随时随地渲染时间.所述<ui:param>
通行证的EL变量为一个facelet模板包括通过<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>
Run Code Online (Sandbox Code Playgroud)
它仅适用于例如计算循环中的和.为此,使用EL 3.0流:
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
Run Code Online (Sandbox Code Playgroud)
只是,当你设置scope
有允许值的一个属性request
,view
,session
,或application
,那么它会立即在视图生成时评估,并存储在指定的范围内.
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
Run Code Online (Sandbox Code Playgroud)
这将仅评估一次,并#{dev}
在整个应用程序中可用.
在JSF迭代组件(如<h:dataTable>
,<ui:repeat>
等)中使用JSTL时,或者当JSTL标记属性依赖于JSF事件的结果(例如preRenderView
模型中提交的表单值或视图构建时期间不可用的表单值)时,使用JSTL可能只会导致意外结果.因此,仅使用JSTL标记来控制JSF组件树构建的流程.使用JSF UI组件来控制HTML输出生成的流程.不要将var
迭代的JSF组件绑定到JSTL标记属性.不要依赖JSTL标记属性中的JSF事件.
任何时候你认为你需要通过binding
一个通道绑定一个组件到一个支持bean ,或者findComponent()
在一个支持bean中使用Java代码创建/操作它的子代new SomeComponent()
,然后你应该立即停止并考虑使用JSTL.由于JSTL也是基于XML的,因此动态创建JSF组件所需的代码将变得更易读和可维护.
重要的是要知道,当引用JSTL标记属性中的视图范围bean时,早于2.1.18的Mojarra版本在部分状态保存方面存在错误.整个视图范围的bean将新的重建,而不是从视图树(仅仅是因为完整视图树还没有提供在点JSTL运行)检索.如果您期望或通过JSTL标记属性在视图作用域中存储某些状态,那么它将不会返回您期望的值,或者它将在视图后恢复的实际视图范围内的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>
Run Code Online (Sandbox Code Playgroud)
@ViewScoped
在标记处理程序中失败要查看JSTL标记有用的一些真实世界示例(即在构建视图时真正正确使用),请参阅以下问题/答案:
至于具体的功能需求,如果要有条件地呈现 JSF组件,请改用rendered
JSF HTML组件上的属性,特别是如果#{lpc}
表示JSF迭代组件的当前迭代项,如<h:dataTable>
或<ui:repeat>
.
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
Run Code Online (Sandbox Code Playgroud)
或者,如果您想有条件地构建(创建/添加)JSF组件,那么继续使用JSTL.这比new SomeComponent()
在java中冗长的做法要好得多.
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
Run Code Online (Sandbox Code Playgroud)
Boz*_*zho 13
使用
<h:panelGroup rendered="#{lpc.verbose}">
...
</h:panelGroup>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
82125 次 |
最近记录: |