Risposte:
I <c:xxx>
tag JSTL sono tutti gestori di tag e vengono eseguiti durante il tempo di creazione della vista , mentre i <h:xxx>
tag JSF sono tutti componenti dell'interfaccia utente e vengono eseguiti durante il tempo di rendering della vista .
Si noti che dal di JSF proprie <f:xxx>
e <ui:xxx>
tag solo quelle che non si estendono da UIComponent
sono anche taghandlers, ad esempio <f:validator>
, <ui:include>
, <ui:define>
, ecc Quelli che si estendono da UIComponent
sono anche componenti JSF UI, ad esempio <f:param>
, <ui:fragment>
, <ui:repeat>
, ecc Dai componenti JSF UI solo l' id
e binding
attributi sono valutato anche durante il tempo di costruzione della vista. Pertanto, la risposta di seguito relativa al ciclo di vita JSTL si applica anche agli attributi id
e ai binding
componenti JSF.
Il tempo di creazione della vista è quel momento in cui il file XHTML / JSP deve essere analizzato e convertito in un albero componente JSF che viene quindi archiviato a partire UIViewRoot
dal file FacesContext
. Il tempo di rendering della vista è quel momento in cui l'albero dei componenti JSF sta per generare HTML, a partire da UIViewRoot#encodeAll()
. Quindi: i componenti dell'interfaccia utente JSF e i tag JSTL non vengono sincronizzati come ci si aspetterebbe dalla codifica. È possibile visualizzarlo come segue: JSTL viene eseguito dall'alto verso il basso, producendo l'albero dei componenti JSF, quindi è il turno di JSF di eseguire dall'alto verso il basso di nuovo, producendo l'output HTML.
<c:forEach>
vs <ui:repeat>
Ad esempio, questo markup Facelets che scorre su 3 elementi usando <c:forEach>
:
<c:forEach items="#{bean.items}" var="item">
<h:outputText id="item_#{item.id}" value="#{item.value}" />
</c:forEach>
... crea durante il tempo di costruzione della vista tre <h:outputText>
componenti separati nella struttura dei componenti JSF, rappresentati approssimativamente in questo modo:
<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}" />
... che a loro volta generano individualmente il loro output HTML durante il tempo di rendering della vista:
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
Si noti che è necessario garantire manualmente l'unicità degli ID componente e che anche quelli vengano valutati durante il tempo di costruzione della vista.
Mentre questo Facelets markup iterando su 3 elementi utilizzando <ui:repeat>
, che è un componente dell'interfaccia utente JSF:
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
... finisce già così com'è nell'albero del componente JSF per cui lo stesso <h:outputText>
componente è durante il tempo di rendering della vista che viene riutilizzato per generare output HTML in base al round di iterazione corrente:
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
Si noti che <ui:repeat>
essendo un NamingContainer
componente già assicurato l'unicità dell'ID client in base all'indice di iterazione; non è inoltre possibile utilizzare EL id
nell'attributo dei componenti figlio in questo modo poiché viene anche valutato durante il tempo di costruzione della vista mentre #{item}
è disponibile solo durante il tempo di rendering della vista. Lo stesso vale per un h:dataTable
e simili componenti.
<c:if>
/ <c:choose>
vsrendered
Come altro esempio, questo markup Facelets aggiunge in modo condizionale diversi tag usando <c:if>
(puoi anche usare <c:choose><c:when><c:otherwise>
per questo):
<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
aggiungerà solo <h:inputText>
il componente all'albero dei componenti JSF:
<h:inputText ... />
Mentre questo markup Facelets:
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
... finirà esattamente come sopra nella struttura dei componenti JSF indipendentemente dalla condizione. Questo può quindi finire in un albero dei componenti "gonfio" quando ne hai molti e sono in realtà basati su un modello "statico" (cioè field
non cambia mai durante almeno l'ambito della vista). Inoltre, potresti riscontrare problemi EL quando hai a che fare con sottoclassi con proprietà aggiuntive nelle versioni Mojarra precedenti alla 2.2.7.
<c:set>
vs <ui:param>
Non sono intercambiabili. I <c:set>
set di una variabile nel campo di applicazione EL, che è accessibile solo dopo la posizione tag durante il tempo di visualizzazione di compilazione, ma ovunque nella vista durante la visualizzazione tempo di rendering. Il <ui:param>
passa una variabile EL a un modello facelet incluso via <ui:include>
, <ui:decorate template>
o <ui:composition template>
. Le versioni precedenti di JSF avevano dei bug per cui la <ui:param>
variabile è disponibile anche al di fuori del modello Facelet in questione, questo non dovrebbe mai essere fatto affidamento.
Il <c:set>
senza scope
attributo si comporterà come un alias. Non memorizza nella cache il risultato dell'espressione EL in alcun ambito. Può quindi essere perfettamente utilizzato all'interno, ad esempio iterando i componenti JSF. Pertanto, ad esempio, di seguito funzionerà bene:
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
Non è adatto solo per il calcolo della somma in un ciclo. Per questo invece usa il flusso EL 3.0 :
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
Solo, quando si imposta l' scope
attributo con uno dei valori ammissibili request
, view
, session
, o application
, allora sarà valutata subito durante il tempo di visualizzazione di compilazione e memorizzati nell'ambito specificato.
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
Questo sarà valutato solo una volta e disponibile come #{dev}
nell'intera applicazione.
Utilizzando JSTL può portare a risultati inaspettati quando viene utilizzato all'interno componenti JSF iterazione come <h:dataTable>
, <ui:repeat>
ecc, o quando gli attributi tag JSTL dipendono risultati degli eventi JSF come preRenderView
o scritte valori di modulo nel modello che non sono disponibili durante la visualizzazione del tempo di costruzione . Quindi, utilizzare i tag JSTL solo per controllare il flusso della costruzione dell'albero dei componenti JSF. Utilizzare i componenti dell'interfaccia utente JSF per controllare il flusso di generazione dell'output HTML. Non associare i var
componenti JSF iteranti agli attributi dei tag JSTL. Non fare affidamento sugli eventi JSF negli attributi dei tag JSTL.
Ogni volta che pensi di dover associare un componente al backing bean tramite binding
, o afferrarne uno tramite findComponent()
, e creare / manipolare i suoi figli usando il codice Java in un backing bean con new SomeComponent()
e cosa no, allora dovresti immediatamente smettere e considerare invece l'uso di JSTL. Poiché anche JSTL è basato su XML, il codice necessario per creare dinamicamente componenti JSF diventerà molto più leggibile e gestibile.
È importante sapere che le versioni di Mojarra precedenti alla 2.1.18 avevano un bug nel salvataggio parziale dello stato quando si faceva riferimento a un bean con ambito vista in un attributo tag JSTL. L'intero bean con ambito vista verrà ricreato di recente anziché recuperato dall'albero della vista (semplicemente perché l'albero della vista completo non è ancora disponibile nel punto in cui viene eseguito JSTL). Se ti aspetti o memorizzi un certo stato nel bean con ambito vista da un attributo tag JSTL, allora non restituirà il valore che ti aspetti, o sarà "perso" nel bean con ambito vista reale che viene ripristinato dopo la vista l'albero è costruito. Nel caso in cui non sia possibile eseguire l'aggiornamento a Mojarra 2.1.18 o versioni successive, la soluzione è disattivare il salvataggio parziale dello stato web.xml
come di seguito:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
@ViewScoped
errore nei gestori di tagPer vedere alcuni esempi del mondo reale in cui i tag JSTL sono utili (ad esempio, se utilizzati correttamente durante la creazione della vista), vedere le seguenti domande / risposte:
Per quanto riguarda i requisiti funzionali concreti, se si desidera eseguire il rendering condizionale dei componenti JSF, utilizzare invece l' rendered
attributo sul componente HTML JSF, in particolare se #{lpc}
rappresenta l'elemento attualmente iterato di un componente iterante JSF come <h:dataTable>
o <ui:repeat>
.
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
Oppure, se si desidera creare (creare / aggiungere) componenti JSF in modo condizionale, continuare a utilizzare JSTL. È molto meglio che fare verbosamente new SomeComponent()
in Java.
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
<ui:repeat>
sia un gestore di tag (a causa di questa riga, " Nota che JSF è proprio <f:xxx>
e <ui:xxx>
... ") proprio come <c:forEach>
e quindi, viene valutato al momento della creazione della vista (di nuovo proprio come <c:forEach>
) . In tal caso, non ci dovrebbero essere differenze visibili e funzionali tra <ui:repeat>
e <c:forEach>
? Non capisco cosa significhi esattamente quel paragrafo :)
<f:xxx>
e i <ui:xxx>
tag di JSF che non si estendono UIComponent
sono anche gestori di tag. " Tenta di implicare che <ui:repeat>
è anche un gestore di tag perché <ui:xxx>
include anche <ui:repeat>
? Ciò dovrebbe quindi significare che <ui:repeat>
è uno dei componenti <ui:xxx>
che si estende UIComponent
. Quindi, non è un gestore di tag. (Alcuni di essi potrebbero non estendersi UIComponent
. Quindi, sono gestori di tag).
<c:set>
senza scope
crea un alias dell'espressione EL invece di impostare il valore valutato nell'ambito di destinazione. Prova scope="request"
invece, che valuterà immediatamente il valore (durante il tempo di creazione della vista) e lo imposterà come attributo di richiesta (che non verrà "sovrascritto" durante l'iterazione). Sotto le coperte, crea e imposta un ValueExpression
oggetto.
ClassNotFoundException
. Le dipendenze di runtime del progetto sono interrotte. Molto probabilmente stai usando un server non JavaEE come Tomcat e hai dimenticato di installare JSTL, oppure hai accidentalmente incluso sia JSTL 1.0 che JSTL 1.1+. Perché in JSTL 1.0 il pacchetto è javax.servlet.jstl.core.*
e da JSTL 1.1 questo è diventato javax.servlet.jsp.jstl.core.*
. Indizi per l'installazione JSTL possono essere trovate qui: stackoverflow.com/a/4928309
uso
<h:panelGroup rendered="#{lpc.verbose}">
...
</h:panelGroup>
Per un output simile a uno switch, è possibile utilizzare la faccia dello switch da PrimeFaces Extensions.