【问题标题】:Update a view scoped JSF beans' injected bean更新视图范围的 JSF bean 的注入 bean
【发布时间】:2013-12-12 05:34:39
【问题描述】:
@SessionScoped public class User {
...  //settings, attributes, etc
}

@ViewScoped public class FooController {
@ManagedProperty(value="#{user}") 
private User user;
...
}

@RequestScoped public class LoginController {
@ManagedProperty(value="#{user}") 
private User user;
public String login() {
    //handle Servlet 3.0 based authenticate()... if success, make new User object and slap it into context
    request.getSession().setAttribute("user", user);
    return "?faces-redirect=true";
}
...
}

xhtml 页面几乎在每个页面上都包含登录控件。理想的情况是他们能够登录,页面将刷新,现有的FooController 将引用当前登录的用户,该用户有条件地呈现按钮/元素。行为是发生了登录,但FooController 视图仍然是“有效的”,因此不再尝试再次注入托管 bean。如果我离开页面,然后返回到它[重建视图范围的 bean],用户 bean 会很好地重新注入......但我不希望有那个中间步骤。有什么想法吗?

我尝试了各种形式的FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("user");,希望它能从会话中重新拉出它,但无济于事。我不想在我的 LoginController 中紧密耦合代码来引用专门使 FooController 或 BarController 或任何其他引用用户 bean 的对象无效。

【问题讨论】:

    标签: jsf jsf-2 view-scope managed-property


    【解决方案1】:

    好的,我在开车回家时发现了这一点,这是一个生命周期问题。我试图让 JSF 做一些它不应该对托管 bean 做的事情。

    我没有新建一个User 对象并将其重新分配给LoginControlleruser 的托管实例,而是将登录方法更改为如下所示:

    public String login() {
      //handle Servlet 3.0 based authenticate()... if success...
      User loadedFromDB = someDao.load(principal.getName());
      user.setDefaultPage(loadedFromDB.getDefaultPage());  // NOTE:  The user object IS THE MANAGED BEAN
      user.setDefaultScheme(loadedFromDB.getDefaultScheme());  //  This is the same object the view scoped bean has a ref on, so directly setting that object's fields proliferates that to any other bean that has the user in scope.
      ... //etc... not calling NEW, not reassigning object ref to user
      loadedFromDB = null;
      return "?faces-redirect=true";
    }
    

    这完成了所需要的。谁知道,如果你停止与框架抗争一分钟并使用它,它会帮助你:)

    【讨论】:

      【解决方案2】:

      您为什么要尝试从viewMap(当前会话中@ViewScoped 对象的映射)中删除user@SessionBean)?

      您应该从viewMap 中删除FooController@ViewScoped、bean,即

      FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("fooControl‌​ler");. 
      

      这将摆脱 viewscoped bean 并强制创建一个新的。当然,无论如何,您都需要刷新页面。

      但是,如果您打算删除会话 bean,则应该直接访问会话:

      FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove("user");.
      

      这摆脱了用户对象

      【讨论】:

      • 好吧,目标不是删除用户 bean,而是将更新后的用户对象扩散到任何视图范围的 bean。我测试了您的解决方案,该解决方案有效,但FooController 只是大约 20 个视图范围的 bean 之一,根据用户从哪个页面登录,这些 bean 可能处于活动状态。 [登录表单是一个弹出式面板,几乎包含在每个页面上]。尝试删除 LoginController 的代号 20 多个 bean 似乎是一个纠缠问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-23
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多