Почему JSF сохраняет состояние дерева компонентов?

Кажется, существует разница между состоянием состояния bean состояния и состояния дерева компонентов. Вы можете управлять состоянием bean с помощью аннотаций, таких как @RequestScoped и @SessionScoped, но, похоже, у вас нет выбора в том, сохраняется или нет состояние дерева компонентов (хотя вы можете выбрать, будет ли он сохранен на сервере или клиентом).

Кажется, что состояние дерева компонентов должно быть необходимо только в течение одного запроса в качестве временной структуры данных для обработки запроса. Он должен быть перестроен с нуля для каждого запроса. С сохранением частичного состояния JSF 2.0 улучшается ситуация, поскольку сохраняются только данные формы, но я не понимаю, почему полезно использовать даже данные формы из предыдущего запроса.

Если ваше приложение использует только область запроса

Ответ 1

Поскольку дерево компонентов может быть изменено программно в зависимости от исходного запроса. Это не обязательно воспроизводится при последующем запросе всякий раз, когда данные формы должны обрабатываться.

Далее у меня создается впечатление, что вы думаете, что дерево компонентов также содержит значения модели. Это неправда. Он содержит только ссылки (по языку выражения) для значений модели (управляемые свойства bean). Состояние представления не копирует/дублирует/не содержит состояние модели. Это просто чистое дерево компонентов пользовательского интерфейса. Возможно, ваше замешательство основано на этом. Обратите внимание, что термин "данные формы" должен интерпретироваться как представленные значения и значения модели.

См. также:

Ответ 2

Добавляя к предыдущему ответу, с тех пор как JSF 2.0 по умолчанию используется что-то под названием partial state saving.

Язык описания описания по умолчанию в JSF (Facelets) создает все дерево компонентов из исходного Facelet после каждого запроса и инициализирует компоненты из соответствующих атрибутов тегов. Затем он отмечает состояние.

Каждое последующее изменение состояния затем запоминается как изменение дельты, и это состояние фактически сохраняется. Вполне возможно, что просто нет таких изменений, и тогда состояние представления пуст (из-за ошибки состояние никогда не было действительно пустым, но это было недавно исправлено. См. http://java.net/jira/browse/JAVASERVERFACES-2203 для деталей)

Итак, большой вопрос: что на самом деле в этом состоянии тогда, когда оно не пустое?

Как уже отмечал BalusC, это может привести к динамическим изменениям в дереве компонентов. Эти изменения могут быть инициированы с помощью beans или из статических компонентов. Простым примером такого компонента, который выполняет это динамическое изменение, является компонент таблицы, который создает дочерние компоненты столбца на основе фактического количества столбцов в наборе данных.

Еще одно важное использование для состояния представления - это запоминание значений, которые были изменены внутри компонентов, но не были перенесены в модель. Это могут быть такие вещи, как щелчок переключателя в компоненте переключателя, перемещение ползунка в компоненте набора и т.д.

Один конкретный пример - это компонент viewParam, который запоминает параметр запроса (параметр строки запроса для параметра GET или без лица POST), с которым он был инициализирован. См. Это для получения дополнительной информации об этом: http://arjan-tijms.omnifaces.org/2011/07/stateless-vs-stateful-jsf-view.html

Существует также сильная связь с компонентами состояния, которые запоминают состояние пользовательского интерфейса и преобразование или проверку, которая терпит неудачу. В этом случае компоненты пользовательского интерфейса будут помнить значения, введенные пользователем, и будут помнить, что произошла ошибка преобразования/проверки.

Еще одно использование для состояния - это оптимизация. Некоторые компоненты вычисляют значения, которые они считают дорогостоящими для расчета и хранения их в состоянии представления. Например, компоненты UIInput делают это после первого post-back:

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#869), поэтому, возможно, в будущем мы увидим некоторые изменения.

Возможность отключить состояние для каждого компонента и иметь легкий крюк для восстановления состояния, если инфраструктура не может (как в ASP.NET) также оказаться полезной.