【问题标题】:Session Scoped Managed Bean constructor being called on each page refresh每次页面刷新时都会调用 Session Scoped Managed Bean 构造函数
【发布时间】:2012-05-27 19:22:03
【问题描述】:

我正在使用会话范围的托管 bean 来处理 Java EE 应用程序中的登录。在我对用户进行身份验证后,用户对象将保存在此会话 bean 中。但是,刷新页面后,会话 bean 值消失了。

我正在调试代码,结果是在页面刷新时再次调用会话范围托管 bean 的构造函数,因此使用新用户初始化用户对象。我想这不是正常行为,因为它应该保留在会话中,不是吗?

我正在发布登录托管 bean 的某些部分,包括参数和登录方法。基本上enteredEmail 和enteredPassword 代表登录表单上输入的数据。如果身份验证成功,loggedIn 布尔值将变为 true,并且登录的用户对象存储在 checkedUser 变量中。

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class LoginController  implements Serializable {

@EJB
private LoginSessionBean loginSessionBean;
@EJB
private LecturerFacade lecturerFacade;

private Lecturer checkedUser;
private String enteredEmail;
private String enteredPassword;
private boolean loggedIn;





/** Creates a new instance of loginController */
public LoginController() {
   loggedIn = false;
   checkedUser = new Lecturer();
}
public String login(){
    RequestContext context = RequestContext.getCurrentInstance();
    FacesMessage msg = null;

    this.setCheckedUser(lecturerFacade.findLecturerByEmail(enteredEmail));

    if(loginSessionBean.checkPassword(checkedUser, enteredPassword))
    {
        loggedIn = true;
        msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", checkedUser.getFirstName()+ " " + checkedUser.getLastName());



        FacesContext.getCurrentInstance().addMessage(null, msg);
        context.addCallbackParam("loggedIn", loggedIn);



    }
    return "Index";

我还发布了上述托管 bean 使用的两个 EJB。 LecturerFacade 使用输入的电子邮件检索用户对象,而 loginSessionBean 则检查密码。

@Stateless
public class LecturerFacade extends AbstractFacade<Lecturer> {
@PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;

Logger logger = Logger.getLogger("MyLog");
FileHandler fh;


protected EntityManager getEntityManager() {
    return em;
}

public LecturerFacade() {
    super(Lecturer.class);
}

public Lecturer findLecturerByEmail(String email) {
    try {
        return (Lecturer) this.getEntityManager().createQuery("SELECT l FROM Lecturer l WHERE l.email = :email").setParameter("email", email).getSingleResult();
    } catch (NoResultException e) {
        System.err.println("Caught NOResultException: "+  e.getMessage());
        return null;
    } catch (NonUniqueResultException e) {
        System.err.println("Caught NonUniqueResultException: "+  e.getMessage());
        return null;
    } catch (IllegalStateException e) {
        System.err.println("Caught IllegalStateException: "+  e.getMessage());
        return null;
    }
}

_

@Stateless

public class LoginSessionBean {

// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
@PersistenceContext(unitName = "EffectinetWebPU")
private EntityManager em;

protected EntityManager getEntityManager() {
    return em;
}

public void setEntityManager(EntityManager em) {
    this.em = em;
}



public boolean checkPassword(Lecturer user, final String enteredPassword) {
    if (user.getPassword().equals(enteredPassword)) {
        return true;
    } else {
        return false;
    }
}

}

如果有人对出了什么问题有任何建议,请告诉我

我使用 glassfish 3.1 作为应用服务器和 Primefaces 作为 JSF 库。另外,我已经检查并从正确的包中导入了 sessionScoped 注释,而不是从 javax.enterprise ...

【问题讨论】:

  • 你做错了什么。请发布代码和/或配置的相关部分
  • 如何认证用户?
  • 我刚刚发布了一些代码部分。谢谢你的帮助!
  • 也许你的会话在你的代码中某处被破坏了,例如在LoginSessionBean?
  • @MattHandy 我不认为会话可能在 EJB 中被破坏。无论如何,我在问题中添加了两个 EJB。可以的话请看一下..谢谢

标签: jsf


【解决方案1】:

因此您的问题就在这里:

<p:menuitem value="Logout" ... onclick="#{loginController.logout()}"/>

onclick 属性应该代表一个 JavaScript 处理函数,当最终用户单击该元素时,该处理函数将在网络浏览器中执行。类似的东西

onclick="alert('You have clicked this element!')"

onclick 属性也接受 ValueExpression,因此您甚至可以让 JSF/EL 相应地自动生成其值:

onclick="#{bean.onclickFunction}"

public String getOnclickFunction() {
    return "alert('You have clicked this element!')";
}

因此,在呈现页面时会评估所有 EL。在您的特定情况下,每次评估 EL 时都会调用 logout() 方法,因此每次呈现页面时都会使会话无效!

您需要将它绑定到一个带有MethodExpression 的属性,例如&lt;h:commandLink action&gt;&lt;h:commandButton action&gt;,在这种特殊情况下为&lt;p:menuitem action&gt;

<p:menuitem value="Logout" ... action="#{loginController.logout()}"/>

这可以通过理解基本的 HTML 和 JavaScript 概念并记住 JSF 最终生成 HTML/CSS/JS 来理解。在浏览器中打开JSF页面,右键查看源码实现。

【讨论】:

    【解决方案2】:

    好吧,我今天设法解决了。这就是问题所在,虽然我无法解释原因:

    我使用 Primefaces 3.2 作为 JSF 库,所以这是索引页面的主菜单。

    <h:form>
            <p:menubar >
                <p:menuitem id="registerLink" value="Register" rendered="#{!loginController.loggedIn}" onclick="registerDialog.show()" /> 
    
                <p:menuitem id="loginLink" value="Login" rendered="#{!loginController.loggedIn}" onclick="loginDialog.show()" />
    
                <p:submenu label="Units" rendered="true"> 
                    <p:menuitem id="addNew" value="Add New" onclick="createUnitDialog.show()" />
    
                    <p:menuitem id="myUnits" value="My Units" onclick="" />
                </p:submenu>        
    
                <p:menuitem id="results" value="Results/Statistics" rendered="#{loginController.loggedIn}" onclick=""/>
    
                <p:menuitem id="profile" value="My Profile" rendered="#{loginController.loggedIn}" onclick=""/>
    
                <p:menuitem id="logout" value="Logout" rendered="#{loginController.loggedIn}" onclick="#{loginController.logout()}"/>
    
            </p:menubar>
        </h:form>
    

    在为整个代码设置断点后,我发现在每次页面刷新时都会调用 logout() 方法,该方法应该销毁托管 bean。我不知道为什么会发生这种情况,因为应该在单击注销菜单项时调用它。

    但是,将onclick="#{loginController.logout()} 更改为action="#{loginController.logout()} 后,问题就解决了。

    我查看了 Primefaces 的文档,但没有任何地方解释过这种行为

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-02
      • 1970-01-01
      • 2014-01-15
      • 2011-07-06
      • 2014-01-04
      • 2019-08-06
      • 1970-01-01
      • 2017-12-07
      相关资源
      最近更新 更多