我有一个托管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。
答案 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的表达式时放入会话对象,这不是这里的情况。