托管bean有时是空的,有时不是

时间:2010-11-19 12:35:38

标签: java web-applications jsf

我有一个托管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。

2 个答案:

答案 0 :(得分:4)

如果会话范围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实例,因此所有实例变量都将在所有请求/会话之间共享。换句话说:它不是线程安全的。

答案 1 :(得分:2)

似乎您在创建之前尝试使用bean,因为PhaseListener在第一阶段中触发。你有没有试过把它转移到后期阶段?

编辑: 您可以在crate标志设置为true的情况下访问会话:

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

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