Відповіді:
<c:xxx>
Теги JSTL - це всі теґандлери, і вони виконуються під час збирання перегляду , тоді як <h:xxx>
теги JSF - всі компоненти інтерфейсу, і вони виконуються під час візуалізації перегляду .
Зверніть увагу , що з власних JSF, <f:xxx>
і <ui:xxx>
тегів тільки ті , у яких НЕ простягаються від UIComponent
також taghandlers, наприклад <f:validator>
, <ui:include>
, <ui:define>
і т.д. Ті , які простягаються від UIComponent
також компонент JSF призначеного для користувача інтерфейсу, наприклад <f:param>
, <ui:fragment>
, <ui:repeat>
і т.д. З компонентів для користувача інтерфейсу JSF тільки id
і binding
атрибути є також оцінюється під час збирання перегляду. Таким чином, нижченаведена відповідь щодо життєвого циклу JSTL також стосується id
та binding
атрибутів компонентів JSF.
Час складання представлення - це той момент, коли файл XHTML / JSP повинен бути розібраний і перетворений у дерево компонентів JSF, яке потім зберігається UIViewRoot
з FacesContext
. Час візуалізації перегляду - це той момент, коли дерево компонентів JSF збирається генерувати HTML, починаючи з UIViewRoot#encodeAll()
. Отже: компоненти інтерфейсу JSF та теги 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, приблизно представлені так:
<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>
Зауважте, що вам потрібно вручну забезпечити унікальність ідентифікаторів компонента, і що вони також оцінюються під час збирання перегляду.
Хоча ця розмітка Facelets розміщує ітерацію над 3 елементами <ui:repeat>
, що є компонентом інтерфейсу JSF:
<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
компонент вже забезпечив унікальність ідентифікатора клієнта на основі індексу ітерації; так само неможливо використовувати EL в id
атрибуті дочірніх компонентів таким чином, оскільки він також оцінюється під час складання перегляду, поки #{item}
він доступний лише під час візуалізації перегляду. Те саме стосується h:dataTable
і подібних компонентів.
<c:if>
/ <c:choose>
протиrendered
Як інший приклад, ця розмітка 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>
... буде лише у випадку type = TEXT
додавання <h:inputText>
компонента до дерева компонентів JSF:
<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
вона ніколи не змінюється протягом принаймні області перегляду). Також ви можете зіткнутися з проблемою EL, коли ви маєте справу з підкласами з додатковими властивостями у версіях Mojarra до 2.2.7.
<c:set>
проти <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>
Це не підходить, наприклад, для обчислення суми в циклі. Для цього замість цього використовуйте потік 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 може призвести до несподіваних результатів лише при використанні всередині ітераційних компонентів JSF, таких як <h:dataTable>
, <ui:repeat>
тощо, або коли атрибути тегів JSTL залежать від результатів подій JSF, таких як preRenderView
або подані значення форми в моделі, які недоступні під час збирання перегляду . Отже, використовуйте теги JSTL лише для управління потоком побудови компонентів JSF. Використовуйте компоненти JSF UI для управління потоком генерації вихідного HTML. Не прив'язуйте var
ітераційних компонентів JSF до атрибутів тегів JSTL. Не покладайтеся на події JSF в атрибутах тегів JSTL.
Коли ви думаєте, що вам потрібно прив’язати компонент до резервного файлу через binding
або захопити його через findComponent()
, а також створити / маніпулювати його дітьми, використовуючи код Java в резервному бобі, new SomeComponent()
а що ні, тоді слід негайно зупинитись і розглянути можливість використання JSTL. Оскільки JSTL також базується на XML, код, необхідний для динамічного створення компонентів JSF, стане набагато кращим для читання та ремонтування.
Важливо знати, що версії Mojarra, старші 2.1.18, мали помилку в частковому збереженні стану при посиланні на переглянуту квасолю в атрибуті тегу JSTL. Весь об'єм обширного виду буде знову відтворений замість вилученого з дерева перегляду (просто тому, що повне дерево перегляду ще не доступне в точці запуску JSTL). Якщо ви очікуєте або зберігаєте деякий стан у переглянутому діапазоні за атрибутом тегу JSTL, він не поверне значення, яке ви очікуєте, або воно буде «втрачено» в реальному діапазоні масштабування, який буде відновлено після перегляду будується дерево. Якщо ви не можете оновити до 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>
це один із компонентів, <ui:xxx>
що розширюються UIComponent
. Отже, це не обробник тегів. (Деякі з них можуть не поширюватися UIComponent
. Отже, вони обробляють теги) Чи це?
<c:set>
без scope
створює псевдонім виразу EL замість встановлення оціненого значення в цільовій області. Спробуйте scope="request"
замість цього, який негайно оцінить значення (дійсно під час збирання перегляду) і встановить його як атрибут запиту (який не буде "переписано" під час ітерації). Під обкладинками він створює та встановлює ValueExpression
об’єкт.
ClassNotFoundException
. Залежності від вашого проекту порушені. Швидше за все, ви використовуєте не-JavaEE-сервер, наприклад Tomcat, і ви забули встановити 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.