Introducción
Todas las <c:xxx>
etiquetas JSTL son manipuladores de etiquetas y se ejecutan durante el tiempo de creación de la vista , mientras que las <h:xxx>
etiquetas JSF son todos componentes de la interfaz de usuario y se ejecutan durante el tiempo de representación de la vista .
Tenga en cuenta que a partir del propio JSF <f:xxx>
y <ui:xxx>
etiquetas solamente aquellas que no se extienden desde UIComponent
también son taghandlers, por ejemplo <f:validator>
, <ui:include>
, <ui:define>
, etc. Los que se extienden desde UIComponent
también son componentes JSF interfaz de usuario, por ejemplo <f:param>
, <ui:fragment>
, <ui:repeat>
, etc. A partir de componentes de interfaz de usuario JSF sólo el id
y binding
atributos son también evaluado durante el tiempo de construcción de la vista. Por lo tanto, la respuesta a continuación sobre el ciclo de vida JSTL también se aplica a los atributos id
y binding
de los componentes JSF.
El tiempo de compilación de la vista es el momento en que el archivo XHTML / JSP debe analizarse y convertirse en un árbol de componentes JSF que luego se almacena a partir UIViewRoot
de FacesContext
. El tiempo de representación de la vista es el momento en que el árbol de componentes JSF está a punto de generar HTML, comenzando por UIViewRoot#encodeAll()
. Entonces: los componentes de la interfaz de usuario JSF y las etiquetas JSTL no se ejecutan en sincronización como cabría esperar de la codificación. Puede visualizarlo de la siguiente manera: JSTL se ejecuta primero de arriba a abajo, produciendo el árbol de componentes JSF, luego le toca a JSF volver a ejecutar de arriba a abajo, produciendo la salida HTML.
<c:forEach>
vs <ui:repeat>
Por ejemplo, este marcado de Facelets iterando sobre 3 elementos usando <c:forEach>
:
<c:forEach items="#{bean.items}" var="item">
<h:outputText id="item_#{item.id}" value="#{item.value}" />
</c:forEach>
... crea durante el tiempo de compilación de la vista tres <h:outputText>
componentes separados en el árbol de componentes JSF, aproximadamente representados así:
<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}" />
... que a su vez generan individualmente su salida HTML durante el tiempo de visualización:
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
Tenga en cuenta que debe garantizar manualmente la unicidad de los ID de componentes y que también se evalúan durante el tiempo de construcción de la vista.
Si bien este marcado de Facelets itera sobre 3 elementos usando <ui:repeat>
, que es un componente JSF UI:
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
... ya termina como está en el árbol de componentes JSF, por lo que el mismo <h:outputText>
componente está durante el tiempo de representación de la vista y se reutiliza para generar resultados HTML basados en la ronda de iteración actual:
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
Tenga en cuenta que el hecho de <ui:repeat>
ser un NamingContainer
componente ya garantizaba la unicidad de la ID del cliente basada en el índice de iteración; Tampoco es posible utilizar EL en el id
atributo de componentes secundarios de esta manera, ya que también se evalúa durante el tiempo de creación de la vista, mientras #{item}
que solo está disponible durante el tiempo de representación de la vista. Lo mismo es cierto para un h:dataTable
y componentes similares.
<c:if>
/ <c:choose>
vsrendered
Como otro ejemplo, este marcado de Facelets agrega condicionalmente diferentes etiquetas usando <c:if>
(también puede usar <c:choose><c:when><c:otherwise>
para esto):
<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>
... en caso de que type = TEXT
solo agregue el <h:inputText>
componente al árbol de componentes JSF:
<h:inputText ... />
Si bien este marcado de Facelets:
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
... terminará exactamente como se indica arriba en el árbol de componentes JSF independientemente de la condición. Por lo tanto, esto puede terminar en un árbol de componentes "hinchado" cuando tiene muchos de ellos y en realidad se basan en un modelo "estático" (es decir, field
que nunca cambia durante al menos el alcance de la vista). Además, puede encontrarse con problemas EL cuando trata con subclases con propiedades adicionales en las versiones de Mojarra anteriores a 2.2.7.
<c:set>
vs <ui:param>
No son intercambiables. Los <c:set>
conjuntos de una variable en el ámbito EL, que sólo se puede acceder después de la ubicación de la etiqueta durante el tiempo de vista de construcción, sino en cualquier parte de la vista durante la vista el tiempo de renderización. El <ui:param>
pasa una variable de EL a una plantilla Facelet incluye a través de <ui:include>
, <ui:decorate template>
o <ui:composition template>
. Las versiones anteriores de JSF tenían errores por los cuales la <ui:param>
variable también está disponible fuera de la plantilla de Facelet en cuestión, esto nunca se debe confiar.
El <c:set>
sin un scope
atributo se comportará como un alias. No almacena en caché el resultado de la expresión EL en ningún ámbito. Por lo tanto, puede usarse perfectamente en el interior, por ejemplo, iterando componentes JSF. Por lo tanto, por ejemplo, a continuación funcionará bien:
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
Solo no es adecuado, por ejemplo, para calcular la suma en un bucle. Para eso, en su lugar, use el flujo EL 3.0 :
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
Solamente, cuando se establece el scope
atributo con uno de los valores permisibles request
, view
, session
, o application
, entonces será evaluado inmediatamente durante el tiempo de vista de construcción y se almacena en el ámbito especificado.
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
Esto se evaluará solo una vez y estará disponible como en #{dev}
toda la aplicación.
Utilice JSTL para controlar la construcción de árbol de componentes JSF
El uso de JSTL solo puede generar resultados inesperados cuando se usa dentro de componentes iterativos JSF como <h:dataTable>
, <ui:repeat>
etc., o cuando los atributos de la etiqueta JSTL dependen de los resultados de eventos JSF como preRenderView
valores de formulario enviados en el modelo que no están disponibles durante el tiempo de construcción de la vista . Por lo tanto, use etiquetas JSTL solo para controlar el flujo de la construcción de árbol de componentes JSF. Utilice los componentes de la interfaz de usuario JSF para controlar el flujo de la generación de salida HTML. No enlace los var
componentes JSF iterativos a los atributos de etiqueta JSTL. No confíe en los eventos JSF en los atributos de etiqueta JSTL.
Cada vez que piense que necesita vincular un componente al backing bean via binding
, o tomar uno via findComponent()
, y crear / manipular sus hijos usando el código Java en un backing bean con new SomeComponent()
y lo que no, debe detenerse inmediatamente y considerar usar JSTL en su lugar. Como JSTL también está basado en XML, el código necesario para crear dinámicamente componentes JSF será mucho más fácil de leer y mantener.
Es importante saber que las versiones de Mojarra anteriores a 2.1.18 tenían un error en el ahorro de estado parcial al hacer referencia a un bean de ámbito de vista en un atributo de etiqueta JSTL. La visión de conjunto de frijol de ámbito sería recién recreado en lugar de recuperar de la visión árbol (simplemente porque el árbol visión completa aún no está disponible en las carreras punto de JSTL). Si espera o almacena algún estado en el bean de ámbito de vista mediante un atributo de etiqueta JSTL, no devolverá el valor que espera, o se "perderá" en el bean de ámbito de vista real que se restaura después de la vista El árbol está construido. En caso de que no pueda actualizar a Mojarra 2.1.18 o más reciente, la solución consiste en desactivar el ahorro de estado parcial de la web.xml
siguiente manera:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
Ver también:
Para ver algunos ejemplos del mundo real en los que las etiquetas JSTL son útiles (es decir, cuando se usan realmente correctamente durante la creación de la vista), consulte las siguientes preguntas / respuestas:
En una palabra
En cuanto a su requisito funcional concreto, si desea representar los componentes JSF condicionalmente, utilice el rendered
atributo en el componente HTML JSF, en particular si #{lpc}
representa el elemento iterado actualmente de un componente iterativo JSF como <h:dataTable>
o <ui:repeat>
.
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
O, si desea construir (crear / agregar) componentes JSF condicionalmente, siga usando JSTL. Es mucho mejor que hacerlo new SomeComponent()
en Java.
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
Ver también:
<ui:repeat>
es un manejador de etiquetas (debido a esta línea, " Tenga en cuenta que JSF es propio<f:xxx>
y<ui:xxx>
... ") exactamente igual<c:forEach>
y, por lo tanto, se evalúa en el momento de la compilación de la vista (nuevamente igual que igual<c:forEach>
) . Si es así, entonces, ¿no debería haber ninguna diferencia visible y funcional entre<ui:repeat>
y<c:forEach>
? No entiendo qué significa exactamente ese párrafo :)<f:xxx>
y las<ui:xxx>
etiquetas de JSF que no se extiendenUIComponent
también son manejadores de etiquetas ", intenta implicar que<ui:repeat>
también es un manejador de etiquetas porque<ui:xxx>
también incluye<ui:repeat>
. Esto debería significar que<ui:repeat>
es uno de los componentes<ui:xxx>
que se extiendeUIComponent
. Por lo tanto, no es un manejador de etiquetas. (Algunos de ellos pueden no extenderseUIComponent
. Por lo tanto, son manejadores de etiquetas) ¿Lo hace?<c:set>
sinscope
crea un alias de la expresión EL en lugar de establecer el valor evaluado en el alcance objetivo. En suscope="request"
lugar, intente , que evaluará inmediatamente el valor (durante el tiempo de creación de la vista) y lo establecerá como atributo de solicitud (que no se "sobrescribirá" durante la iteración). Debajo de las cubiertas, crea y establece unValueExpression
objeto.ClassNotFoundException
. Las dependencias de tiempo de ejecución de su proyecto están rotas. Lo más probable es que esté utilizando un servidor que no sea JavaEE como Tomcat y haya olvidado instalar JSTL, o haya incluido accidentalmente tanto JSTL 1.0 como JSTL 1.1+. Porque en JSTL 1.0 el paquete esjavax.servlet.jstl.core.*
y desde JSTL 1.1 esto se ha convertidojavax.servlet.jsp.jstl.core.*
. Las pistas para instalar JSTL se pueden encontrar aquí: stackoverflow.com/a/4928309utilizar
fuente
Para una salida tipo interruptor, puede usar la cara del interruptor de PrimeFaces Extensions.
fuente