Почему JSF сохраняет состояние дерева компонентов?
Похоже, существует разница между состоянием управляемого компонента и состоянием дерева компонентов. Вы можете контролировать состояние управляемого компонента с помощью аннотаций, таких как @RequestScoped и @SessionScoped, но, похоже, у вас нет выбора, сохранять или нет состояние дерева компонентов (хотя вы можете выбрать, будет ли оно сохранено на сервере или клиенте).).
Кажется, что состояние дерева компонентов должно быть необходимо только на время одного запроса в качестве временной структуры данных, чтобы помочь обработать запрос. Это должно быть восстановлено с нуля для каждого запроса. С JSF 2.0 частичное сохранение состояния улучшает ситуацию, потому что сохраняются только данные формы, но я не понимаю, почему полезно иметь даже данные формы из предыдущего запроса.
Если ваше приложение использует только компоненты, управляемые областью действия запроса, особенно нет смысла сохранять состояние дерева компонентов между запросами. Даже если в вашем приложении есть управляемые bean-компоненты области сеанса, я предполагаю, что управляемые bean-компоненты будут содержать состояние, и дерево компонентов по-прежнему не будет нуждаться в каком-либо состоянии между запросами.
2 ответа
Потому что дерево компонентов может быть изменено программно в зависимости от исходного запроса. Это не обязательно воспроизводится в последующем запросе всякий раз, когда данные формы должны быть обработаны.
Кроме того, у меня сложилось впечатление, что вы думаете, что дерево компонентов также содержит значения модели. Это неправда. Он содержит только ссылки (по языку выражения) на значения модели (свойства управляемого компонента). Состояние представления не копирует / не дублирует / не содержит состояние модели. Это просто дерево компонентов UI. Возможно, ваше замешательство основано на этом. Обратите внимание, что термин "данные формы" следует интерпретировать как представленные значения и значения модели.
Смотрите также:
Добавление к предыдущему ответу, начиная с JSF 2.0, называется partial state saving
используется по умолчанию.
Язык описания представлений по умолчанию в JSF (Facelets) создает каждое дерево компонентов из исходного Facelet после каждого запроса и инициализирует компоненты из их соответствующих атрибутов тега. Затем он отмечает состояние.
Каждое последующее изменение состояния затем запоминается как изменение дельты, и именно это состояние фактически сохраняется. Вполне может оказаться, что таких изменений просто нет, и тогда состояние представления будет пустым (из-за ошибки состояние никогда не было действительно пустым, но это было недавно исправлено. См. http://java.net/jira/browse/JAVASERVERFACES-2203 для подробностей)
Итак, главный вопрос в том, что же на самом деле в этом состоянии, когда оно не пустое?
Как уже отмечал BalusC, это может содержать динамические изменения в дереве компонентов. Эти изменения могут быть инициированы либо из резервных компонентов, либо из статических компонентов. Простым примером типа компонента, который выполняет это динамическое изменение, является компонент таблицы, который создает дочерние компоненты столбцов на основе фактического количества столбцов в наборе данных.
Другое важное использование для состояния представления - запоминание значений, которые были изменены внутри компонентов, но не были вставлены в модель. Это могут быть такие вещи, как щелчок переключателя в компоненте переключателя, перемещение ползунка в компоненте набора и т. Д.
Одним конкретным примером является viewParam
компонент, который запоминает параметр запроса (параметр строки запроса для GET или параметр POST без лиц), с которым он был инициализирован. См. Это для получения дополнительной информации об этом: http://arjan-tijms.omnifaces.org/2011/07/stateless-vs-stateful-jsf-view.html
Существует также тесная связь с компонентами с отслеживанием состояния, которые запоминают состояние пользовательского интерфейса и преобразование или проверку, которая не выполняется. В этом случае компоненты пользовательского интерфейса запомнят значения, введенные пользователем, и запомнят, что произошла ошибка преобразования / проверки.
Еще одно использование для государства - оптимизация. Некоторые компоненты вычисляют значения, которые они считают дорогостоящими, чтобы рассчитать и сохранить их в состоянии просмотра. Например, компоненты UIInput делают это после первого постбека:
private boolean validateEmptyFields(FacesContext ctx) {
if (validateEmptyFields == null) {
ExternalContext extCtx = ctx.getExternalContext();
String val = extCtx.getInitParameter(VALIDATE_EMPTY_FIELDS_PARAM_NAME);
if (val == null) {
val = (String) extCtx.getApplicationMap().get(VALIDATE_EMPTY_FIELDS_PARAM_NAME);
}
if (val == null || "auto".equals(val)) {
validateEmptyFields = isBeansValidationAvailable(ctx);
} else {
validateEmptyFields = Boolean.valueOf(val);
}
}
return validateEmptyFields;
}
После этого validateEmptyFields
хранится в состоянии просмотра, поэтому его не нужно вычислять заново после отправки следующей формы. Улучшение было бы, если бы пользователи могли выбирать между перерасчетом или сохранением (хорошо известная оптимизация пространства-времени).
Сама концепция состояния - это то, что мешало разработке веб-приложений с самого начала. Каждый хочет иметь взаимодействие, которое по существу является состоянием, но почти никто не хочет справляться с этим или даже думать об этом.
JSF пытается дать ответ здесь, но он явно не идеален и есть возможности для улучшения. Требование JSF о возможности восстановления состояния просмотра (даже пустого состояния просмотра) может быть проблематичным, хотя, как было упомянуто в другом ответе, оно обеспечивает неявную защиту от CSRF. JSF 2.2 получит более явную защиту CSRF (см., Например, http://arjan-tijms.omnifaces.org/p/jsf-22.html), поэтому, возможно, мы увидим некоторые изменения здесь в будущем.
Возможность отключения состояния для каждого компонента и простое подключение для восстановления состояния в случае, если инфраструктура не может (как в ASP.NET), также может оказаться полезной.