JSF:会话作用域托管bean的属性变为null

时间:2014-05-12 23:26:24

标签: jsf null managed-bean java-ee-7 session-scope

我正在玩JavaEE 7并尝试使用简单的登录机制编写一个webapp。

有一个持有JPA的EJB实体类,名为User,用于保存有关用户的数据。在WAR中,名为UserManagedBean的会话作用域托管bean负责跟踪当前用户,因此它具有类型User的属性,该属性在有人成功登录时设置。过滤器正在监视此属性的值,并在必要时重定向到登录页面。当然,UserUserManagedBean都是可序列化的(实现接口并且不包含任何不可序列化的内容)。

我的问题是,在成功登录后,刷新页面会将我引回登录页面,而我之前设置的user属性现在为空(实际上这就是过滤器触发的原因重定向)。

以下是我的尝试:

  • 分离的逻辑和数据:UserManagedBean现在只有这一个属性和一些辅助方法,没有EJB,没有任何与Java魔法相关的东西。
  • 尝试将web.xml中的javax.faces.STATE_SAVING_METHOD上下文参数设置为服务器和客户端,没有任何更改。
  • 已验证会话作用域托管bean保持不变:只创建其中一个,但在从登录页面导航后,用户的值会以某种方式为空。
  • 根据NetBeans调试器,除了将user字段设置为登录用户外,不会访问user字段。
  • 指定自定义序列化方法显示在实验期间未对UserManagedBean进行序列化或反序列化。
  • 在Chrome中进行调试表明会话ID已保存在Cookie中,并且在User的值丢失时不会更改。
  • 未检测到任何例外情况。

我必须遗漏一些微不足道的东西,任何帮助都会受到赞赏。

更新:这确实是微不足道的,与JSF或托管bean无关,请参阅下面的答案。)

我的代码如下:

@Entity(name = "USERS") public class User implements Serializable { private static final long serialVersionUID = 1L; @Id private String username; private boolean administrator; private byte[] salt; private byte[] passwordHash; public String getUsername() { return username; } public void setUsername(String userName) { this.username = userName; } public boolean isAdministrator() { return administrator; } public void setAdministrator(boolean administrator) { this.administrator = administrator; } public byte[] getSalt() { return salt; } public void setSalt(byte[] salt) { this.salt = salt; } public byte[] getPasswordHash() { return passwordHash; } public void setPasswordHash(byte[] passwordHash) { this.passwordHash = passwordHash; } @Override public int hashCode() { int hash = 0; hash += (username != null ? username.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof User)) { return false; } User other = (User) object; if ((this.username == null && other.username != null) || (this.username != null && !this.username.equals(other.username))) { return false; } return true; } @Override public String toString() { return "hu.bme.aut.mv.testbay.ejb.entities.User[ id=" + username + " ]"; } } 上课:

UserManagedBean

@ManagedBean(name = "userManagedBean") @SessionScoped public class UserManagedBean implements Serializable { private static final long serialVersionUID = 1L; private User currentUser; public User getCurrentUser() { return currentUser; } public void setCurrentUser(User user) { this.currentUser = user; } public boolean isLoggedIn() { return currentUser != null; } public boolean isAdmin() { return currentUser != null && currentUser.isAdministrator(); } public String logout() { currentUser = null; return "/faces/index.xhtml"; } /** * Creates a new instance of UserManagedBean */ public UserManagedBean() { System.out.println("UserManagedBean constructed!"); } } 上课:

doBeforeProcessing

过滤器(HttpSession session = ((HttpServletRequest) request).getSession(false); UserManagedBean userManagedBean = (session != null) ? (UserManagedBean) session.getAttribute("userManagedBean") : null; if (userManagedBean == null || userManagedBean.getCurrentUser() == null) { ((HttpServletResponse)response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/faces/login.xhtml"); } ):

LoginManagedBean

更新

重要的是要注意用户已正确设置一次,并按原样转换到欢迎屏幕。但是,nex请求会将用户属性设置为空。

触发身份验证的代码位于请求范围@ManagedBean @RequestScoped public class LoginManagedBean implements Serializable { @EJB private AuthenticationSessionBeanLocal authBean; @ManagedProperty("#{userManagedBean}") private UserManagedBean userManagedBean; @PostConstruct public void Dummy() { User user = userManagedBean.getCurrentUser(); } public UserManagedBean getUserManagedBean() { return userManagedBean; } public void setUserManagedBean(UserManagedBean userManagedBean) { this.userManagedBean = userManagedBean; } private String username; private String password; //Some getters and setters... //... public String login() throws NoSuchAlgorithmException { if (authenticate(username, password)) { if (userManagedBean.getCurrentUser().isAdministrator()) return "/faces/admin/welcome.xhtml?faces-redirect=true"; else return "/faces/testing/welcome.xhtml?faces-redirect=true"; } return null; } private boolean authenticate(String username, String password) throws NoSuchAlgorithmException { userManagedBean.setCurrentUser(authBean.authenticate(username, password)); if (userManagedBean.getCurrentUser() == null) return false; return true; } //Constructor and methods... //... } 类:

{{1}}

2 个答案:

答案 0 :(得分:1)

这确实是一个愚蠢的错误。

NetBeans断点没有发出信号,但是确实通过logout函数访问了该字段,该函数在每次导航后调用。原来我误用了PrimeFaces组件。我想将注销outcome的{​​{1}}属性设置为commandButton上的注销方法,但NetBeans自动完成在方法名称后面放了一对括号,我没有注意到。因此,EL不会收到UserManagedBean属性不像outcome那样的错误并且应该将路径作为字符串接收的错误,而是EL评估了action方法以将结果设置为返回的url登录页面,但该方法也以静默方式注销用户。

我唯一想知道的是NetBeans如何在set方法和在访问字段时应该触发的字段断点中破坏。

答案 1 :(得分:0)

您可以将变量放在视图中(即View作用域)并使用getter和setter检索/修改它。 这样也可以通过模拟视图响应以更好的方式测试控制器。