【问题标题】:Managed bean is sometimes null and sometimes not托管 bean 有时为空,有时不是
【发布时间】:2011-05-12 14:52:59
【问题描述】:

我有一个托管 bean LoginBean:

@ManagedBean(name = "loginBean")
@SessionScoped
public class LoginBean implements Serializable {

    private String email, password;
    private BasicUser user;

    /** Creates a new instance of LoginBean */
    public LoginBean() {
    }

    public void setUser(BasicUser user) {
        this.user = user;
    }

    public BasicUser getUser() {
        return user;
    }

   ...
 }

然后是获取会话 loginBean 的 PhaseListener。

public class FacebookSignInListener implements PhaseListener, UserService {
private LoginBean bean;    
....

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }

    @Override
    public void afterPhase(PhaseEvent event) {
    HttpSession session = (HttpSession) event.getFacesContext().getExternalContext().getSession(true);
    bean = (LoginBean) session.getAttribute("loginBean");
    bean.setUser(facebookUser);
}
    @Override
    public void beforePhase(PhaseEvent event) {
    FacesContext fc = FacesContext.getCurrentInstance();
    request = (HttpServletRequest) fc.getExternalContext().getRequest();
    boolean isLoginPage =
            (fc.getViewRoot().getViewId().indexOf("welcome") > -1);
    if (isLoginPage) {
        try {
            FBOauth fbo = new FBOauth(this);
            fbo.doLogin(request);
        } catch (IOException ex) {
            Logger.getLogger(FacebookSignInListener.class.getName()).log(Level.SEVERE, "Could not exchange code for access_token. Page where not found.", ex);
        }
    }
}

    @Override
    public boolean authFacebookLogin(String accessToken, FacesContext fc) throws FacebookException {
        if (accessToken != null) {
            FacebookClient facebookClient = new DefaultFacebookClient(accessToken);
            User fbUser = facebookClient.fetchObject("me", User.class);

            UserHelper uh = new UserHelper();
            FacebookUser facebookUser = (FacebookUser) uh.getByFacebookId(fbUser.getId());           
// Does the user already exist and is he already connected with facebook.
            if (facebookUser != null) {             
                return true;
            }
         }
      }
}

当我在管理控制台按启动应用程序部署后,通过 facebook 登录我的应用程序时,下面的代码没有问题。我可以注销并重新登录,仍然没有问题。如果我随后更改浏览器并尝试通过 facebook 登录,我会得到一个 NullPointerException

bean.setUser(facebookUser)

如果我关闭第一个浏览器,再次打开并尝试通过 facebook 登录,也会发生这种情况。为什么会这样?

我正在使用 Glassfish v3。

【问题讨论】:

    标签: java web-applications jsf


    【解决方案1】:

    如果会话范围的 bean 是 null,那么它只是意味着它还没有为会话创建。这可能发生在新会话的第一个请求期间。您必须自己创建它并自己将其放入会话范围内。 JSF 只会在会话的剩余部分中重用它。

    您获取会话范围 bean 的方式有点笨拙。您正在从 JSF 的底层获取原始 Servlet API。您也可以只使用ExternalContext#getSessionMap() 来管理会话属性。

    Map<String, Object> sessionMap = externalContext.getSessionMap();
    LoginBean loginBean = (LoginBean) sessionMap.get("loginBean");
    if (loginBean == null) {
        loginBean = new LoginBean();
        sessionMap.put("loginBean", loginBean);
    }
    // ...
    

    请注意,您不应将 bean 声明为 PhaseListener 的实例变量。即在应用程序的整个生命周期中只有一个 PhaseListener 实例,因此所有实例变量将在所有请求/会话之间共享。换句话说:它不是线程安全的。

    【讨论】:

      【解决方案2】:

      似乎您在创建 bean 之前尝试使用它,因为您的 PhaseListener 在第一个阶段触发。您是否尝试将其转移到后期?

      编辑: 您访问将 crate 标志设置为 true 的会话:

      HttpSession session = (HttpSession) externalContext.getSession(true);
      

      因此,您新创建的会话不会包含任何会话范围的 bean。 当引用 bean 的表达式被求值时,框架将实例化会话范围的 Bean 并放入会话对象中,这不是这里的情况。

      【讨论】:

      • 布尔标志不会强制刷新会话。如果 servletcontainer 不存在,它只是指示 servletcontainer 创建新的。原因确实是由于在您的第一句话中挂钩太早(当 bean 尚未创建时)。
      • 对,但如果没有活动会话,它将创建一个新会话。在这种情况下,会话范围的 bean 将不可用。或者我在这里错过了什么? ;-)
      • 您的回答暗示这是由于将 create 标志设置为 true 造成的。这是错误的。
      • 我让 PhaseListener 监听 RENDER_RESPONSE,但是当我将代码移动到 beforePhase 时问题仍然存在,这是我需要的,因为(如果没有)某些内容已写入 ResponseStream,然后我无法重定向。奇怪的是,在管理控制台中按下启动后第一次不会发生这种情况。如上所述。
      猜你喜欢
      • 1970-01-01
      • 2015-02-28
      • 2013-04-16
      • 1970-01-01
      • 2012-08-27
      • 1970-01-01
      • 2016-07-11
      • 2012-10-02
      • 1970-01-01
      相关资源
      最近更新 更多