【问题标题】:Access and modify property(ies) of an Application-Scoped Managed Bean from Session Listener从 Session Listener 访问和修改 Application-Scoped Managed Bean 的属性
【发布时间】:2012-05-15 14:52:11
【问题描述】:

我需要访问应用程序范围的托管 bean 以从 HttpSessionListener 中修改某些属性。

我已经使用了类似以下的东西:

@Override
public void sessionDestroyed(HttpSessionEvent se) {
    HttpSession session = se.getSession();
    User user = userService.findBySessionId(session.getId());    

    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();

     ApplicationScopedBean appBean = (ApplicationScopedBean) externalContext.getApplicationMap().get("appBean");

     appBean.getConnectedUsers().remove(user);
}

externalContext = FacesContext.getCurrentInstance().getExternalContext() 已经在这里导致了一个空指针异常,即使它没有,我也不确定 appBean 是否可以通过上述方式访问。

有什么想法吗?

【问题讨论】:

  • 可能您的页面没有使用 FacesServlet。显示您的 web.xml JSF servlet 配置和映射以及页面的全名。
  • 似乎无法从 HttpSessionListener 中使用 FacesContext.getCurrentInstance() 获取 FacesContext;就像从 Servlet 无法做到这一点一样。也许如果你能得到 ServletContext 你可以做类似 getServletContext().getAttribute("appBean");

标签: java jsf jakarta-ee jsf-2


【解决方案1】:

FacesContext 仅在服务于由调用FacesServlet 的网络浏览器发起的 HTTP 请求的线程中可用。在会话销毁期间,不一定意味着 HTTP 请求。会话通常由容器管理的后台线程销毁。这不会通过FacesServlet 调用HTTP 请求。所以你不应该期望FacesContext 在会话销毁期间总是在那里。只有在 JSF 托管 bean 中调用 session.invalidate() 时,FacesContext 才可用。

如果您的应用程序范围的托管 bean 由 JSF @ManagedBean 管理,那么很高兴知道 JSF 将其作为 ServletContext 的属性存储在幕后。 ServletContext 反过来在会话侦听器中由HttpSession#getServletContext() 提供。

所以,应该这样做:

@Override
public void sessionDestroyed(HttpSessionEvent se) {
    HttpSession session = se.getSession();
    User user = userService.findBySessionId(session.getId());    
    ApplicationScopedBean appBean = (ApplicationScopedBean) session.getServletContext().getAttribute("appBean");
    appBean.getConnectedUsers().remove(user);
}

如果您正在运行支持 Servlet 3.0 的容器,另一种方法是让您的应用程序范围的 bean 实现 HttpSessionListener 并在构造时将其自身注册为此类。这样您就可以直接引用connectedUsers 属性。

@ManagedBean
@ApplicationScoped
public class AppBean implements HttpSessionListener {

    public AppBean() {
        ServletContext context = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
        context.addListener(this);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        User user = userService.findBySessionId(session.getId());    
        connectedUsers.remove(user);
    }

    // ...
}

另一个替代方法是将User 保留在会话范围内作为会话范围的托管bean。然后,您可以使用@PreDestroy 注释来标记应在会话被销毁时调用的方法。

@ManagedBean
@SessionScoped
public class User {

    @ManagedProperty("#{appBean}")
    private AppBean appBean;

    @PreDestroy
    public void destroy() {
        appBean.getConnectedUsers().remove(this);
    }

    // ...
}

这还有一个额外的好处,那就是User 在 EL 上下文中可用作 #{user}

【讨论】:

    猜你喜欢
    • 2014-01-04
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 2013-12-12
    • 2012-08-07
    • 2012-04-09
    相关资源
    最近更新 更多