使用JSF 2.2时,在每个回发请求上重新创建@ViewScoped bean

Rim*_*ima 8 jsf postback primefaces view-scope jsf-2.2

我有一个类似于这篇文章的问题和来自@BalusC的3个解决方案的答案,但是:

  • 我没有使用上面提到的EL表达式
  • 我不想再使用第二种解决方案(这对我来说足够复杂)
  • 和部分状态保存设置为false.

我的代码如下:

index.xhtml:

<?xml version="1.0" encoding="windows-1256" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title>Insert title here</title>
    </h:head>
    <h:body>
        <h:form>
            <p:panelMenu id="westMenu">
                <p:submenu id="sub1" label="System Monitor">
                    <p:menuitem id="menu1" value="live monitoring" 
                            action="#{menusBean.activateMenu('sub1_menu1')}" 
                            update=":centerPane,westMenu" 
                            disabled="#{menusBean.active['sub1_menu1']}" />
                    <p:menuitem id="menu2" value="reports" 
                            action="#{menusBean.activateMenu('sub1_menu2')}"
                            update=":centerPane,westMenu" 
                            disabled="#{menusBean.active['sub1_menu2']}" />
                </p:submenu>
                <p:submenu id="sub2" label="Charging System Nodes" />
                <p:submenu id="sub3" label="Additional Nodes" />
            </p:panelMenu>
        </h:form>
        <h:panelGroup id="centerPane">
            ...
        </h:panelGroup>
    </h:body>
</html>
Run Code Online (Sandbox Code Playgroud)

MenusBean.java:

package menus;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

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

@ManagedBean
@ViewScoped
public class MenusBean implements Serializable{

    private static final long serialVersionUID = -7793281454064343472L;
    private String mainPage="sub1_menu1";
    private Map<String, Boolean> active;

    public MenusBean(){
        System.out.println("MenusBean created");
        active = new HashMap<>();
        active.put(mainPage, true);
        active.put("sub1_menu2", false);
    }

    public boolean activateMenu(String page){
        active.put(mainPage, false);
        active.put(page, true);     
        mainPage = page;
        for (Map.Entry<String, Boolean> e : active.entrySet())
            System.out.println(e.getKey()+":"+e.getValue());

        return true;
    }

    public Map<String, Boolean> getActive() {
        return active;
    }
}
Run Code Online (Sandbox Code Playgroud)

执行时,我得到:

MenusBean created
MenusBean created
MenusBean created

这是怎么造成的,我该如何解决?

Bal*_*usC 34

这个,

import javax.faces.view.ViewScoped;
Run Code Online (Sandbox Code Playgroud)

JSF 2.2引入的CDI特定注释,旨在与CDI特定的bean管理注释结合使用@Named.

但是,您正在使用特定于JSF的bean管理批注@ManagedBean.

import javax.faces.bean.ManagedBean;
Run Code Online (Sandbox Code Playgroud)

然后,您应该使用同一个javax.faces.bean软件包提供的任何范围.右边@ViewScoped就在那边:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class MenusBean implements Serializable{
Run Code Online (Sandbox Code Playgroud)

如果使用错误的组合,则bean将表现为@RequestScopedbean并在每次调用时重新创建.

或者,如果您的环境支持CDI(GlassFish/JBoss/TomEE with Weld,OpenWebBeans等),那么您也可以替换@ManagedBean@Named:

import javax.inject.Named;
import javax.faces.view.ViewScoped;

@Named
@ViewScoped
public class MenusBean implements Serializable{
Run Code Online (Sandbox Code Playgroud)

建议转到CDI.特定于JSF的bean管理注释是未来JSF/Java EE版本中的弃用词,因为一切都在向CDI缓慢移动/统一.

  • 嗯,这是尴尬.该bean现在由JSF或CDI管理吗?你试过另一个吗?你是否绝对肯定重建/重新部署成功并且浏览器缓存是干净和清晰的?(Chrome中的Ctrl + Shift + N). (2认同)