Как работает атрибут связывания в JSF? Когда и как его следует использовать?
Есть много материалов, дифференцирующих value
атрибут и binding
атрибут в JSF.
Мне интересно, как оба подхода отличаются друг от друга. Дано:
public class User {
private String name;
private UICommand link;
// Getters and setters omitted.
}
<h:form>
<h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>
Это довольно просто, что происходит, когда value
атрибут указан. Геттер бежит, чтобы вернуть name
стоимость имущества User
боб. Значение выводится в вывод HTML.
Но я не мог понять, как binding
работает. Как сгенерированный HTML поддерживает связь с link
собственность User
фасоль?
Ниже приведена соответствующая часть сгенерированного вывода после ручного украшения и комментирования (обратите внимание, что идентификатор j_id_jsp_1847466274_1
был автоматически сгенерирован и что есть два скрытых виджета ввода). Я использую Sun JSF RI, версия 1.2.
<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
id="j_id_jsp_1847466274_1" method="post" name="j_id_jsp_1847466274_1">
<input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
<a href="#" onclick="...">Name</a>
<input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
type="hidden" value="-908991273579182886:-7278326187282654551">
</form>
Где binding
хранится здесь?
2 ответа
Как это работает?
Когда представление JSF (файл Facelets/JSP) будет построено / восстановлено, будет создано дерево компонентов JSF. На данный момент, время сборки представления, все binding
атрибуты оцениваются ( наряду с id
атрибуты и обработчики тегов, такие как JSTL). Когда компонент JSF необходимо создать перед добавлением в дерево компонентов, JSF проверит, binding
атрибут возвращает предварительно созданный компонент (т.е. не null
) и если да, то используйте его. Если он не создан, то JSF автоматически создаст компонент "обычным способом" и вызовет установщик позади binding
атрибут с автоматически созданным экземпляром компонента в качестве аргумента.
В результате он связывает ссылку на экземпляр компонента в дереве компонентов с переменной области видимости. Эта информация никоим образом не видна в сгенерированном HTML-представлении самого компонента. Эта информация никоим образом не имеет отношения к сгенерированному выводу HTML в любом случае. Когда форма отправлена и представление восстановлено, дерево компонентов JSF просто перестраивается с нуля, и все binding
атрибуты будут просто переоценены, как описано в предыдущем абзаце. После воссоздания дерева компонентов JSF восстановит состояние представления JSF в дереве компонентов.
Экземпляры компонентов находятся в области запроса!
Важно знать и понимать, что конкретные экземпляры компонентов эффективно ограничены запросами. Они создаются заново при каждом запросе, а их свойства заполняются значениями из состояния просмотра JSF во время фазы просмотра восстановления. Таким образом, если вы связываете компонент со свойством бина-компонента, тогда бэк-компонент не должен находиться в более широкой области, чем область запроса. Смотрите также главу 3.1.5 спецификации JSF 2.0:
3.1.5 Привязки компонентов
...
Привязки компонентов часто используются вместе с JavaBean-компонентами, которые динамически создаются с помощью средства создания управляемых компонентов (см. Раздел 5.8.1 "VariableResolver и VariableResolver по умолчанию"). Настоятельно рекомендуется, чтобы разработчики приложений помещали управляемые bean-компоненты, на которые указывают выражения привязки компонентов, в область "запроса". Это связано с тем, что для помещения его в сессию или область приложения потребуется безопасность потоков, поскольку экземпляры UIComponent зависят от работы внутри одного потока. Также возможно негативное влияние на управление памятью при помещении привязки компонента в область "сеанса".
В противном случае экземпляры компонента распределяются между несколькими запросами, что может привести к ошибкам " дублирования идентификатора компонента " и "странным" поведениям, потому что валидаторы, преобразователи и прослушиватели, объявленные в представлении, повторно присоединяются к существующему экземпляру компонента из предыдущего запроса (запросов). Симптомы очевидны: они выполняются несколько раз, еще один раз с каждым запросом в той же области, к которой привязан компонент.
И при большой нагрузке (то есть, когда несколько разных HTTP-запросов (потоков) обращаются к одному и тому же экземпляру компонента и манипулируют им в одно и то же время), вы можете рано или поздно столкнуться с аварийным завершением приложения, например, с застрявшим потоком в UIComponent.popComponentFromEL или потоками Java. при 100% загрузке ЦП с использованием richfaces UIDataAdaptorBase и его внутреннего HashMap, или даже какого-то "странного" IndexOutOfBoundsException
или же ConcurrentModificationException
прямо из исходного кода реализации JSF, когда JSF занят сохранением или восстановлением состояния просмотра (т. е. трассировка стека указывает saveState()
или же restoreState()
методы и тому подобное).
С помощью binding
на свойствах бобов - плохая практика
Независимо от того, используя binding
таким образом, привязка целого экземпляра компонента к свойству bean-компонента, даже для bean-объекта, находящегося в области запроса, в JSF 2.x встречается довольно редко и, как правило, не является наилучшей практикой. Это указывает на дизайнерский запах. Обычно вы объявляете компоненты на стороне представления и связываете их атрибуты времени выполнения, например: value
и, возможно, другие, как styleClass
, disabled
, rendered
и т. д. для нормальных свойств бобов. Затем вы просто манипулируете именно тем свойством бина, которое вам нужно, вместо того, чтобы захватывать весь компонент и вызывать метод установки, связанный с атрибутом.
В тех случаях, когда компонент должен быть "динамически собран" на основе статической модели, лучше использовать теги времени построения представления, такие как JSTL, при необходимости в файле тегов, вместо createComponent()
, new SomeComponent()
, getChildren().add()
и что "нет. См. Также Как преобразовать фрагмент старого JSP в какой-нибудь эквивалент JSF?
Или, если компонент должен быть "динамически визуализирован" на основе динамической модели, тогда просто используйте компонент итератора (<ui:repeat>
, <h:dataTable>
, так далее). Смотрите также Как динамически добавлять компоненты JSF.
Композитные компоненты - это совсем другая история. Совершенно законно связывать компоненты внутри <cc:implementation>
к вспомогательному компоненту (т.е. компоненту, обозначенному <cc:interface componentType>
, См. Также разделение java.util.Date на два поля h:inputText, представляющие часы и минуты с помощью f:convertDateTime, и Как реализовать динамический список с помощью составного компонента JSF 2.0?
Использовать только binding
в местном масштабе
Однако иногда вы хотели бы узнать о состоянии другого компонента внутри конкретного компонента, чаще, чем в случаях использования, связанных с проверкой действия / значения. Для этого binding
Атрибут может использоваться, но не в сочетании со свойством компонента. Вы можете просто указать в локальной области EL уникальное имя переменной в binding
атрибут так binding="#{foo}"
и компонент находится во время ответа рендеринга в другом месте в том же виде, что и непосредственно UIComponent
ссылка доступна #{foo}
, Вот несколько связанных вопросов, где такое решение использовалось в ответе:
- Подтвердите ввод как требуется, только если определенная командная кнопка нажата
- Как отобразить компонент, только если другой компонент не отображается?
- Индекс строки таблицы данных JSF 2 без модели данных
- Простые лица зависят от selectOneMenu и required="true"
- При необходимости проверьте группу полей, если заполнено хотя бы одно из них.
- Как изменить класс CSS для поля ввода и метки, если проверка не пройдена?
- Получение JSF-определенного компонента с Javascript
Используйте выражение EL для передачи идентификатора компонента в составной компонент в JSF
(и это только с прошлого месяца...)
Смотрите также:
- Как использовать связывание компонентов в JSF правильно? (компонент в области запроса в компоненте, определяемом сессией)
- Область видимости: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
- Атрибут Binding приводит к дублированию идентификатора компонента, найденного в представлении
Каждый компонент JSF выводит себя в HTML и имеет полный контроль над тем, какой HTML он создает. JSF может использовать множество приемов, и какой именно из этих приемов будет использоваться, зависит от используемой вами реализации JSF.
- Убедитесь, что каждое из входных данных имеет полностью уникальное имя, поэтому, когда форма отправляется обратно в дерево компонентов, которое ее обработало, легко определить, где каждый компонент может прочитать свою форму значения.
- Компонент JSF может генерировать javascript, который отправляет обратно на сервер, сгенерированный javascript знает, где также связан каждый компонент, потому что он был сгенерирован компонентом.
Для таких вещей, как hlink, вы можете включить информацию о привязке в url как параметры запроса или как часть самого url или как параметры matrx. Например.
http:..../somelink?componentId=123
позволит jsf посмотреть в дереве компонентов, чтобы увидеть, что ссылка 123 была нажата. или это может бытьhtp:..../jsf;LinkId=123
Самый простой способ ответить на этот вопрос - создать страницу JSF только с одной ссылкой, а затем изучить вывод html. Таким образом, вы будете точно знать, как это происходит, используя версию JSF, которую вы используете.