使用JSF #view.attributes map而不是#viewScope存储视图范围的应用程序数据是不是很糟糕?

时间:2014-03-29 14:51:29

标签: java jsf myfaces mojarra view-scope

有人建议我使用#view.attributes地图存储view scoped data that I need to survive even after session destroys(保存客户端状态)。现在它完全符合我的要求,但我只是想确保这不是一个坏习惯或坏事。

我发现这与viewcope map的工作方式完全相同,只是在用户会话被销毁后,它仍能保存数据。

2 个答案:

答案 0 :(得分:3)

在2.0之前的JSF版本中,只能使用UIViewRoot.set / getAttribute在视图中存储对象。

然而,在JSF 2.0中,引入了一个单独的视图范围,可以通过#{viewScope}在EL中使用,也可以使用UIViewRoow.getViewMap()以编程方式使用。建议使用视图范围。它使用保存在UIViewRoot中的Map实现,并以与视图状态中的视图属性相同的方式进行序列化,因此它与视图属性具有相同的生命周期。

<强>更新

来自MyFaces团队的Leonardo Uribe表示:

  

在JSF 2.2中,决定将视图范围bean始终存储在会话中   (看看@ViewScoped注释中的描述   的javadoc)。但是你可以调用facesContext.getViewRoot()并使用   属性图。只需记住必须有Seri​​alizable或的值   实现StateHolder。

所以看起来可移植的方法是使用UIViewRoot中的属性映射。

答案 1 :(得分:0)

建议使用viewScope

。避免使用视图根(一般组件)属性有两个原因:

  1. 理论上,您可能会覆盖视图根组件属性。在实践中,由于属性键是用enum(至少在mojarra中)实现的,因此无法实现

  2. UIComponentBase.getAttributes返回特定的Map实施:AttributesMap。首先,此实现检查组件中是否存在具有相同map密钥名称的方法。如果不是,它会检查内部地图。如果再次找不到它,它会检查组件ValueExpression地图。因此它根本没有效率,并且在非常特殊的情况下,可以导致无限递归。

  3. 请查看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;
    }
    

    考虑到你的必要条件,至少从webapp的角度来看,这没有多大意义。视图状态记住组件状态:从初始状态更改并将在下一步处理的组件模型值。如果这些值不被处理,则不需要长时间记录。我们可以认为它们是“短暂的”。相反,如果必须长时间处理和记住它们,就必须坚持不懈。事实上,我不能认为这种数据的单一案例能够比会话存活更长时间,而且比永久性更短(持久性)。

    你能告诉我们一个现实生活中的例子吗?

    我脑海中最好的例子是记住tabView或手风琴的活动索引,但是这个值可以(并且应该)保留,如果它很重要的话。

    但是每个问题都有一个解决方案,我能想到的第一件事就是你可以实现一个自定义范围,它使用特定的cookie(客户端)值作为关键字将这些值存储在应用程序范围内。