Java 使用JSF#view.attributes映射而不是#viewScope来存储视图范围的应用程序数据是否不好?
有人建议我使用Java 使用JSF#view.attributes映射而不是#viewScope来存储视图范围的应用程序数据是否不好?,java,jsf,myfaces,mojarra,view-scope,Java,Jsf,Myfaces,Mojarra,View Scope,有人建议我使用#view.attributes映射存储(客户端状态保存)。现在,它完美地满足了我的要求,但我只想确保这不是一个坏的做法或做坏事 我发现它的工作原理与viewscope映射完全相同,只是它即使在用户会话被破坏后也能保存数据。在2.0之前的JSF版本中,只有使用UIViewRoot.set/getAttribute才能在视图中存储对象 然而,在JSF2.0中引入了一个单独的视图范围,可以通过#{viewScope}在EL中使用,也可以通过UIViewRoow.getViewMap()
#view.attributes
映射存储(客户端状态保存)。现在,它完美地满足了我的要求,但我只想确保这不是一个坏的做法或做坏事
我发现它的工作原理与viewscope映射完全相同,只是它即使在用户会话被破坏后也能保存数据。在2.0之前的JSF版本中,只有使用UIViewRoot.set/getAttribute才能在视图中存储对象 然而,在JSF2.0中引入了一个单独的视图范围,可以通过#{viewScope}在EL中使用,也可以通过UIViewRoow.getViewMap()编程使用。建议使用视图范围。它是使用保存在UIViewRoot中的映射实现的,并以与W视图状态中的视图属性相同的方式序列化,因此它与视图属性具有相同的生命周期 更新 根据MyFaces团队的莱昂纳多·乌里韦的说法: 在JSF2.2中,决定始终在会话中存储视图范围bean (请查看中@ViewScope注释的说明。) javadoc)。但是您只需调用facesContext.getViewRoot()并使用 属性映射。请记住,这些值必须是可序列化的或 实行国家所有制
因此,似乎可移植的方法是在UIViewRoot中使用属性映射。建议使用
viewScope
。出于以下两个原因,避免使用视图根(通常为组件)属性:
枚举实现的(至少在mojarra中是这样)
UIComponentBase.getAttributes
返回特定的Map
实现:attributemap
。这个实现首先检查组件中是否存在一个名为map key的方法。如果没有,它会检查内部映射。如果再次未找到,则检查组件ValueExpression
map。所以它根本不是有效的,在非常特殊的情况下,可能导致无限递归attributemap.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;
}
公共对象获取(对象keyObj){
字符串键=(字符串)keyObj;
对象结果=空;
if(key==null){
抛出新的NullPointerException();
}
如果(属性为设置键等于(键)){
结果=component.getstateheloper().get(UIComponent.PropertyKeysPrivate.attributesThatAreSet);
}
映射属性=(映射)
component.getStateHelper().get(PropertyKeys.attributes);
if(null==结果){
PropertyDescriptor pd=
getPropertyDescriptor(键);
如果(pd!=null){
试一试{
方法readMethod=pd.getReadMethod();
if(readMethod!=null){
结果=(readMethod.invoke(组件,
空的(对象(数组));
}否则{
抛出新的IllegalArgumentException(键);
}
}捕获(非法访问例外e){
抛开新面孔(e);
}捕获(调用TargetException e){
抛出新的FacesException(例如getTargetException());
}
}else if(属性!=null){
if(attributes.containsKey(键)){
结果=attributes.get(键);
}
}
}
if(null==结果){
ValueExpression ve=组件。getValueExpression(键);
如果(ve!=null){
试一试{
结果=ve.getValue(component.getFacesContext().getELContext());
}捕捉(电子例外e){
抛开新面孔(e);
}
}
}
返回结果;
}
至少从网络应用的角度来看,考虑到你的需求,这没有什么意义。视图状态会记住组件状态:从初始状态更改的组件模型值,将在下一步进行处理。如果这些值不需要处理,那么就不需要长时间的记忆。我们可以把它们看作是“暂时的”。相反,如果它们必须被处理和记住很长一段时间,那么持久性就是方法。事实上,我认为这种数据的生存时间比会话时间长,比永久时间短(持久性)的情况没有一个 你能告诉我们一个真实的例子吗 我脑海中出现的最好的例子是记住tabView或手风琴的活动索引,但是如果这个值很重要的话,它可以(而且应该)保持
然而,每个问题都有一个解决方案,我能想到的第一件事是,您可以实现一个自定义作用域,使用特定的cookie(客户端)值作为键将这些值存储在应用程序作用域中。但是viewscope存储在会话中&因此,当用户会话被破坏时,它会丢失(在我的应用程序中发生得非常快),那么,如何使viewscope数据即使在会话被破坏后仍然存在?我应该为此数据设计自定义实现吗?有什么想法吗?如果您的状态保存方法是服务器,则该视图将在会话中序列化。如果方法是client,则视图状态将被序列化、编码为base64并发送到浏览器,在浏览器中它存储在隐藏字段中,并在执行下一个请求时发送回服务器。因此,即使会话在服务器上过期,客户端也将提供该视图状态,并将成功恢复。查看UIViewRoot的实现,组件属性与视图映射一起保存,因此它们的生命周期应该相同。您使用的是什么JSF实现和版本?感谢Adrian对此进行深入研究。我使用的是
Myfaces 2.2.2
。但我确实试过了