当使用重定向加载网页时,我看不到在 @ViewScoped bean 的 @PostConstruct 方法中生成的菜单

I can not see menu generated in @PostConstruct method in @ViewScoped bean when web page is loaded with redirect

环境:

我想在 ViewScope bean 中加载一个在 @PostConstruct 方法中生成的菜单,但是当加载网页时菜单是无效的。

页面 persona.xhtml 是从另一个网页的重定向加载的,并且 PersonaBean 具有 ViewScope。 PersonaBean init() @PostConstruct 已执行,但网页中未加载任何值。

特定 bean CustomMenuBean(视图范围)已加载,但 CustomMenuBean.menu 在网页中为空,但它在 bean 中有菜单(当我在调试模式下停在那里时 CustomMenuBean.menu 是正确的已加载)。

所以我尝试用一​​个按钮更新 frmMenus 以进行测试,并且在使用以下代码刷新网页后效果很好。

<p:commandButton value="update" action="#{personaBean.doNothing}"  process=":frmMenus" update=":frmMenus"/>

网页persones.xhtml

...
<p:dataTable id="lstPersones" var="item" value="#{personesBean.items}"...>
    <p:ajax event="rowSelect" listener="#{personesBean.onRowSelect}"/>
...

PersonesBean.java

@ViewScoped
@ManagedBean
public class PersonesBean ...
...
    @Override
    public void onRowSelect(SelectEvent event) {
        ...
        HttpServletRequest origRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        String ctxPath = origRequest.getContextPath();
        FacesContext.getCurrentInstance().getExternalContext().redirect(ctxPath + "\gestio\persona.xhtml");
...

网页persona.xhtml

...
<h:form id="frmMenus">
    <div class="layout-menu-container #{usuariPreferenciesBean.menuClass}">
        <div class="nano">
            <div class="nano-content menu-scroll-content">
                <ui:include src="menu_profile.xhtml"/>

                <pu:menu id="mnu_custom" widgetVar="mnu_custom" model="#{customMenuBean.menu}"/>
                <p:separator/>
            </div>
        </div>
    </div>
</h:form>

 <h:form id="frmPersona">
    <!-- person data -->
 </h:form>
 ...

PersonaBean.java

@ViewScoped
@ManagedBean
public class PersonaBean...
...
@ManagedProperty(value = "#{customMenuBean}")
private CustomMenuBean cstmMenuBean; //View scope Bean to store menu

@PostConstruct
public void init() {

    super.init(Persona.class);
    super.setService(service);

    cstmMenuBean.generateMenu(); //create a DefaultMenuModel()

}
...

我不知道我错过了什么。

这个错误好像是一种bug,我没有找到解释。

我只是在@PostConstruct 托管 bean 中从 javascript 执行了一个隐藏按钮。

这不是办法,但它解决了这个补丁的问题。

PersonaBean.java

PrimeFaces.current().executeScript("document.getElementById(\"frmPersona:btnUpdate\").click()");

persona.xhtml

<p:commandButton id="btnUpdate" value="update" action="#{personaBean.doNothing}" process=":frmMenus" update=":frmMenus" style="display:none"/>

在 JSF 中看起来像这样 bug

更新(2012 年 12 月):这确实是 JSF2 中的一个错误。这是先有鸡还是先有蛋的问题。视图作用域 bean 存储在 JSF 视图状态中。因此,视图范围的 bean 仅在恢复视图阶段后可用。但是,绑定属性在恢复视图阶段运行,而视图范围的 bean 尚不可用。这会导致创建一个全新的视图范围 bean 实例,然后由存储在还原的 JSF 视图状态中的真实视图范围 bean 替换。

这被报告为 JSF 问题 1492JSF 规范问题 787 将针对 JSF 2.2 进行修复。在那之前,您最好的选择是专门对请求范围的 bean 使用绑定,或者为特定的功能需求寻找替代方法。

Balus 有一个 article 来处理这个问题或一个非常相似的问题。