Плохо ли использовать карту JSF #view.attributes вместо #viewScope для хранения данных приложения с областью видимости?

Кто-то предложил мне использовать карту #view.attributes для хранения просмотреть ограниченные данные, которые мне нужны, чтобы выжить даже после уничтожения сеанса(с сохранением состояния на стороне клиента). Теперь, когда он идеально подходит для моего требования, я просто хочу убедиться, что это не плохая практика или плохой поступок.

Я обнаружил, что это работает точно так же, как карта области видимости, за исключением того, что она сохраняет данные даже после того, как сеанс пользователя был уничтожен.


person Rajat Gupta    schedule 29.03.2014    source источник


Ответы (2)


В версиях JSF до 2.0 сохранять объекты в представлении можно было только с помощью UIViewRoot.set/getAttribute.

Однако в JSF 2.0 была введена отдельная область представления, которую можно использовать в EL через #{viewScope} или программно с помощью UIViewRoow.getViewMap(). Рекомендуется использовать область представления. Он реализован с использованием карты, которая хранится в UIViewRoot и сериализуется так же, как атрибуты представления в новом состоянии представления, поэтому она имеет тот же срок службы, что и атрибуты представления.

ОБНОВЛЕНИЕ

По словам Леонардо Урибе из команды MyFaces:

В JSF 2.2 было решено всегда хранить bean-компоненты области просмотра в сеансе (взгляните на описание аннотации @ViewScoped в javadoc). Но вы можете просто вызвать FaceContext.getViewRoot() и использовать карту атрибутов. Просто помните, что значения должны быть Serializable или реализовывать StateHolder.

Таким образом, похоже, что переносимым способом является использование карты атрибутов в UIViewRoot.

person Adrian Mitev    schedule 30.03.2014
comment
но viewscope хранится в сеансе и, таким образом, он теряется, когда сеанс пользователя уничтожается (что происходит очень быстро в моем приложении), так как я могу сохранить данные viewscope даже после уничтожения сеанса? Должен ли я разработать пользовательскую реализацию для этих данных? есть идеи? - person Rajat Gupta; 30.03.2014
comment
Представление сериализуется в сеансе, если ваш метод сохранения состояния — сервер. Если метод является клиентским, состояние представления сериализуется, кодируется как base64 и отправляется в браузер, где оно сохраняется в скрытом поле и отправляется обратно на сервер при выполнении следующего запроса. Таким образом, даже если срок действия сеанса на сервере истекает, клиент предоставит это состояние просмотра, и оно будет успешно восстановлено. - person Adrian Mitev; 30.03.2014
comment
Глядя на реализацию UIViewRoot, атрибуты компонента сохраняются вместе с картой представления, поэтому их жизненный цикл должен быть таким же. Какую реализацию и версию JSF вы используете? - person Adrian Mitev; 30.03.2014
comment
Спасибо, Адриан, за то, что углубился в это. Я использую Myfaces 2.2.2. Но я попробовал это на практике, всякий раз, когда я сохраняю карту области просмотра (с сохранением состояния на стороне клиента), я не могу восстановить сохраненные данные области видимости после уничтожения сеанса. Для справки, вот ссылка на эту проблему, размещенную в списке рассылки myfaces, и решение, предложенное некоторыми пользователями (для использования #view.attributes) mail-archive.com/[email protected]/msg59924.html - person Rajat Gupta; 30.03.2014
comment
Вы смотрите на реализацию mojarra и делает ли она это по-другому? - person Rajat Gupta; 30.03.2014
comment
Я смотрю на мохарру. Однако обе реализации JSF должны поддерживать это. - person Adrian Mitev; 30.03.2014
comment
И какая конкретная версия мохарры? Согласно моим тестам, Myfaces 2.2 не поддерживает это. - person Rajat Gupta; 30.03.2014
comment
Что ж, похоже, я был неправ, потому что мое заявление и исходный код, который я ищу, относятся к jsf 2.1. По словам Леонардо Урибе. В JSF 2.2 было решено всегда хранить компоненты области видимости в сеансе (посмотрите описание аннотации @ViewScoped в javadoc). Я обновлю свой ответ здесь. - person Adrian Mitev; 30.03.2014
comment
Да, именно это я и имел в виду в этой ссылке. Итак, каким должно быть мое решение сейчас? Идеи? - person Rajat Gupta; 30.03.2014
comment
Но, как указывает @Michele Mariotti, это вовсе не эффективное/производительное решение, поэтому есть ли какие-либо альтернативные решения. Или мне следует написать свою пользовательскую реализацию (которая сохранит данные с областью просмотра в виде скрытого поля на моих страницах jsf) ? - person Rajat Gupta; 30.03.2014
comment
Я согласен, что это менее эффективно, чем непосредственное использование карты области видимости. Однако я бы не стал беспокоиться о какой-либо производительности здесь, поскольку это было бы проблемой, только если вы храните много атрибутов на карте атрибутов представления. - person Adrian Mitev; 30.03.2014

рекомендуется использовать viewScope. избегайте использования атрибутов корня представления (компонента в целом) по двум причинам:

  1. теоретически существует вероятность того, что вы перезапишете атрибут корневого компонента представления. на практике это невозможно, поскольку ключи атрибутов реализуются с помощью enum (по крайней мере, в мохарре)

  2. UIComponentBase.getAttributes возвращает конкретную реализацию Map: AttributesMap. эта реализация сначала проверяет, существует ли в компоненте метод с тем же именем, что и ключ карты. а если нет, то проверяет внутреннюю карту. если снова не найдено, проверяет карту компонента ValueExpression. так что это вообще неэффективно и, в особом случае, может привести к бесконечной рекурсии.

взгляните на AttributesMap.get, например:

public Object get(Object keyObj) {
    String key = (String) keyObj;
    Object result = null;
    if (key == null) {
        throw new NullPointerException();
    }
    if (ATTRIBUTES_THAT_ARE_SET_KEY.equals(key)) {
        result = component.getStateHelper().get(UIComponent.PropertyKeysPrivate.attributesThatAreSet);
    }
    Map<String,Object> attributes = (Map<String,Object>)
          component.getStateHelper().get(PropertyKeys.attributes);
    if (null == result) {
        PropertyDescriptor pd =
                getPropertyDescriptor(key);
        if (pd != null) {
            try {
                Method readMethod = pd.getReadMethod();
                if (readMethod != null) {
                    result = (readMethod.invoke(component,
                            EMPTY_OBJECT_ARRAY));
                } else {
                    throw new IllegalArgumentException(key);
                }
            } catch (IllegalAccessException e) {
                throw new FacesException(e);
            } catch (InvocationTargetException e) {
                throw new FacesException(e.getTargetException());
            }
        } else if (attributes != null) {
            if (attributes.containsKey(key)) {
                result = attributes.get(key);
            }
        }
    }
    if (null == result) {
        ValueExpression ve = component.getValueExpression(key);
        if (ve != null) {
            try {
                result = ve.getValue(component.getFacesContext().getELContext());
            } catch (ELException e) {
                throw new FacesException(e);
            }
        }
    }

    return result;
}

Думая о своем реквизите, это не имеет большого смысла, по крайней мере, с точки зрения веб-приложения. Состояние просмотра запоминает состояния компонентов: значения модели компонентов, которые изменены по сравнению с начальным состоянием и должны быть обработаны далее. если эти значения не нужно обрабатывать, то и запоминать долго не надо. мы можем думать о них как о «временных». и наоборот, если их нужно обрабатывать и запоминать в течение длительного времени, настойчивость — это путь. действительно, я не могу придумать ни одного случая, чтобы такого рода данные сохранялись дольше, чем сеанс, и короче, чем навсегда (постоянство).

Можете ли вы привести пример из реальной жизни?

лучший пример, который приходит мне на ум, — запомнить активный индекс для tabView или аккордеона, но это значение можно (и нужно) сохранять, если оно важно.

однако у каждой проблемы есть решение, первое, что я могу подумать, это то, что вы можете реализовать пользовательскую область, которая хранит эти значения в области приложения, используя определенное значение файла cookie (клиента) в качестве ключа.

person Michele Mariotti    schedule 30.03.2014
comment
но viewscope хранится в сеансе и, таким образом, он теряется, когда сеанс пользователя уничтожается (что происходит очень быстро в моем приложении), так как я могу сохранить данные viewscope даже после уничтожения сеанса? Должен ли я разработать пользовательскую реализацию для этих данных? есть идеи? - person Rajat Gupta; 30.03.2014