Жизненный цикл JSF и пользовательские компоненты
-
09-06-2019 - |
Вопрос
Есть пара вещей, которые мне трудно понять в связи с разработкой пользовательских компонентов в JSF.Для целей этих вопросов вы можете предположить, что все пользовательские элементы управления используют привязки значений / выражения (не буквальные привязки), но меня также интересуют пояснения к ним.
- Где мне установить значение для привязки значения?Должно ли это происходить при декодировании?Или decode должен сделать что-то еще, а затем установить значение в encodeBegin?
- Чтение из привязки значения - Когда мне считывать данные из привязки значения по сравнению ссчитывание его из submittedvalue и помещение в valuebinding?
- Когда в связи со всем этим вызываются прослушиватели действий в формах?На всех страницах жизненного цикла JSF упоминаются события, происходящие на разных этапах, но мне не совсем понятно, когда вызывается простой прослушиватель commandbutton
Я перепробовал несколько комбинаций, но всегда сталкивался с трудноуловимыми ошибками, которые, как мне кажется, происходят из-за элементарного непонимания жизненного цикла события.
Решение
В приложении есть довольно хорошая диаграмма Спецификация JSF это показывает жизненный цикл запроса, что важно для понимания этого материала.
Эти шаги заключаются в следующем:
- Восстановить вид.Дерево UIComponent перестраивается.
- Применять Значения запроса.Редактируемые компоненты должны реализовывать EditableValueHolder.На этом этапе выполняется обход дерева компонентов и вызывается Процессдекодирует методы.Если компонент не является чем-то сложным, как UIData, он мало что сделает, кроме как вызовет свой собственный расшифровывать способ.Тот Самый расшифровывать метод мало что делает, кроме как находит свой рендерер и вызывает его расшифровывать метод, передающий себя в качестве аргумента.Задача рендерера - получить любое отправленное значение и установить его с помощью setSubmittedValue - заданное значение.
- Проверки процесса.Эта фаза требует Процессные валидаторы который вызовет подтвердить.Тот Самый подтвердить метод принимает отправленное значение, преобразует его с помощью любых преобразователей, проверяет его с помощью любых валидаторов и (при условии, что данные проходят эти тесты) вызывает Установленное значение.Это сохранит значение как локальную переменную.Хотя эта локальная переменная не равна null, она будет возвращена, а не значение из привязки value для любых вызовов Получаем значение.
- Обновление значений модели.Эта фаза требует Процесс обновления.В компоненте ввода это вызовет Обновляемая модель который получит Значение выражения и вызовите его, чтобы установить значение для модели.
- Вызвать приложение.Здесь будут вызваны прослушиватели событий кнопок и так далее (как и навигация, если память не изменяет).
- Визуализировать Ответ.Дерево визуализируется с помощью средств визуализации, и состояние сохраняется.
- Если какой-либо из этих этапов завершится неудачей (например,значение недопустимо), жизненный цикл переходит к отображению ответа.
- После большинства из этих этапов могут запускаться различные события, вызывающие прослушиватели по мере необходимости (например, прослушиватели изменения значения после проверки процесса).
Это несколько упрощенная версия событий.Обратитесь к спецификации для получения более подробной информации.
Я бы задался вопросом, почему вы пишете свой собственный UIComponent.Это нетривиальная задача, и для ее решения требуется глубокое понимание архитектуры JSF.Если вам нужен пользовательский элемент управления, лучше создать конкретный элемент управления, который расширяет существующий UIComponent (как это делает HtmlInputText) с помощью эквивалентного средства визуализации.
Если загрязнение не является проблемой, существует реализация JSF с открытым исходным кодом в виде Apache MyFaces.
Другие советы
Прослушиватели действий, например, для Командная кнопка, вызываются во время Вызвать приложение фаза, которая является последней фазой перед финальным Визуализировать Ответ фаза.Это показано в Жизненный цикл JSF - рисунок 1.
Это единственный фреймворк, который я когда-либо использовал, где создание компонентов - это глубокий сложный процесс, подобный этому.Ни один из других веб-фреймворков (будь то в мире .net или нет) не делает это настолько болезненным, что для меня совершенно необъяснимо.
Некоторые дизайнерские решения, лежащие в основе JSF, начинают приобретать немного больше смысла, если учесть поставленные цели.JSF был разработан для работы с инструментами - он предоставляет множество метаданных для IDE.JSF - это не веб-фреймворк, это MVP фреймворк, который может быть использован в качестве веб-фреймворка.JSF обладает высокой степенью расширения и конфигурирования - вы можете заменить 90% реализации для каждого приложения.
Большая часть этого материала просто усложняет вашу работу, если все, что вы хотите сделать, это вставить дополнительный HTML-элемент управления.
Компонент представляет собой композицию из нескольких базовых компонентов inputtext (и других) , кстати.
Я предполагаю, что фрагменты страницы на основе JSP-includes / tooling не соответствуют вашим требованиям.
Я бы подумал о том, чтобы использовать ваш UIComponentELTag.Создать компонент создать составной элемент управления с базой UIPanel и создать все его дочерние элементы из существующих реализаций.(Я предполагаю, что вы используете JSP / taglibs и делаете несколько других предположений.) Вероятно, вам понадобился бы пользовательский рендерер, если бы ни один из существующих рендереров UIPanel не выполнял эту работу, но рендереры просты.
Лучшая статья, которую я нашел, это Написание компонента Jsf, что касается 2, где я могу прочитать значение для привязки значения в вашем компоненте, у вас есть геттер, который выглядит следующим образом
public String getBar() {
if (null != this.bar) {
return this.bar ;
}
ValueBinding _vb = getValueBinding("bar");
return (_vb != null) ? (bar) _vb.getValue(getFacesContext()) : null;
}
как это попало в getValueBinding?В вашем классе тегов setProperties метод
if (bar!= null) {
if (isValueReference(bar)) {
ValueBinding vb = Util.getValueBinding(bar);
foo.setValueBinding("bar", vb);
} else {
throw new IllegalStateException("The value for 'bar' must be a ValueBinding.");
}
}