试图从会话作用域Bean中调用.getSessionMap()时发生IllegalStateException

试图从会话作用域Bean中调用.getSessionMap()时发生IllegalStateException,session,jsf,illegalstateexception,session-bean,Session,Jsf,Illegalstateexception,Session Bean,我不熟悉Java和JSF。我需要帮助处理一个非法的例外情况。以下是场景: 在我当前的项目中,我有一个会话范围的bean用于应用程序菜单: public final class MenuBean implements Serializable{ private MenuModel model; private FacesContext context = FacesContext.getCurrentInstance(); public MenuModel getMo

我不熟悉Java和JSF。我需要帮助处理一个非法的例外情况。以下是场景:

在我当前的项目中,我有一个会话范围的bean用于应用程序菜单:

public final class MenuBean implements Serializable{  
    private MenuModel model;
    private FacesContext context = FacesContext.getCurrentInstance();

    public MenuModel getModel() {
        return model;
    }

    public MenuBean() {
        updateMenu();
    }

    public void updateMenu(){
        Map session = (Map<String,Object>) context.getExternalContext().getSessionMap();
        EUser user = (EUser) session.get(UserBean.USER_SESSION_KEY);

        ...
    }

    private MethodExpression createMethodExpression(String action) {  
        ...  
    }
}
public final类MenuBean实现可序列化{
私有菜单模型;
私有FacesContext上下文=FacesContext.getCurrentInstance();
公共菜单模型getModel(){
收益模型;
}
公共菜单项(){
updateMenu();
}
public void updateMenu(){
映射会话=(映射)上下文。getExternalContext().getSessionMap();
EUser user=(EUser)session.get(UserBean.user\u session\u KEY);
...
}
私有MethodExpression createMethodExpression(字符串操作){
...  
}
}
在我的逻辑中,我需要更新菜单,所以我这样做:

ExternalContext extContext = context.getExternalContext();
Map sMap = (Map<String,Object>) extContext.getSessionMap();

MenuBean menu = (MenuBean) sMap.get("menuBean");
menu.updateMenu();
ExternalContext extContext=context.getExternalContext();
Map sMap=(Map)extContext.getSessionMap();
MenuBean菜单=(MenuBean)sMap.get(“MenuBean”);
menu.updateMenu();
bean构造得很好,但是当我尝试如上所示手动更新它时,我在update方法
updateMenu()

我不明白出了什么问题,因为在第一次构建菜单时,我可以通过相同的调用获得会话映射

此外,使用NetBeans调试器,我可以看到MenuBean的实例已正确恢复


你们能帮帮我吗?

HTTP请求线程中存储了
FacesContext
。您绝对不应该将其声明为比HTTP请求寿命更长的实例的实例变量并将其分配给该实例(最好是在它已经基于请求的情况下——这是糟糕的设计)。HTTP请求完成时,
FacesContext
实例被释放并失效。在任何后续HTTP请求中,该实例不再有效。这是一个非法国家的手段。这就解释了你看到的非法状态异常

您需要删除以下行:

private FacesContext context = FacesContext.getCurrentInstance();
并修复代码,使其在方法块中仅为threadlocal:

Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
// ...

JSF随后将为您注入它。

Hi BalusC。非常感谢。这就解决了问题。我在一个教程中看到了那个(糟糕的)设计,但后来我改变了bean的范围,没有注意到这可能发生。我不太理解@ManagedProperty是如何工作的。容器将如何解析“#{user}”?我必须定义它吗?它只是在构造
MenuBean
之后,对EL表达式求值,并直接用检索到的对象调用getter方法。这里我假设您的
UserBean.USER\u SESSION\u键
的值为
USER
,因此它在EL范围内有效地可用,如
{USER}
。但就我对JSF的理解而言,这个EL表达式不应该像“#{userBean.user}”一样吗?我不知道,因为在处理常量时,代码中没有这个细节。但是它应该与您在
UserBean.USER\u SESSION\u KEY
中使用的属性名称相同,并且与您在XHTML文件中从会话范围获取用户时使用的EL表达式相同。
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
// ...
public final class MenuBean implements Serializable {  

    @ManagedProperty("#{user}")
    private EUser user;

    // ...
}