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

Posted

技术标签:

【中文标题】使用 JSF 2.2 时在每个回发请求上重新创建 @ViewScoped bean【英文标题】:@ViewScoped bean recreated on every postback request when using JSF 2.2 【发布时间】:2013-12-13 14:36:45 【问题描述】:

我遇到了与this post 类似的问题,@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>

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;
    

执行时,我得到:

MenusBean 创建 MenusBean 创建 MenusBean 创建

这是怎么引起的,我该如何解决?

【问题讨论】:

【参考方案1】:

这个,

import javax.faces.view.ViewScoped;

是JSF 2.2-introduced CDI-specific 注释,旨在与特定于CDI 的bean 管理注释@Named 结合使用。

但是,您使用的是特定于 JSF 的 bean 管理注释 @ManagedBean

import javax.faces.bean.ManagedBean;

然后您应该使用由相同的javax.faces.bean package 提供的任何范围。右边@ViewScoped在那边:

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

@ManagedBean
@ViewScoped
public class MenusBean implements Serializable

如果您使用了错误的组合,该 bean 将表现为 @RequestScoped bean,并在每次调用时重新创建。

或者,如果您的环境支持 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

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

【讨论】:

ok awsome,这解决了问题,但只是部分 :( ,在更改注释并加载页面后,它工作正常,但是当我进入“报告”菜单时,它开始再次创建又一次,当我回到“实时监控”菜单时,它会再创建一个并停止。有什么想法吗? 嗯,这很尴尬。 bean 现在是由 JSF 还是 CDI 管理?你试过另一个吗?您是否绝对肯定重建/重新部署成功并且浏览器缓存干净清晰? (在 Chrome 中为 Ctrl+Shift+N)。 老实说,我不知道 CDI 是什么,但我没有 javax.inject 包,所以我想它是由 JSF 管理的(对不起,这里是菜鸟)。 here 是我的项目;我清除了FF中的缓存并尝试使用eclipse内置浏览器,它们都给出了相同的结果。 好的。鉴于您手头没有 CDI,我可以假设您使用 Tomcat 作为服务器吗? 抱歉,无法在 Tomcat 7.0.47 上使用 Mojarra 2.2.4 以及问题中以当前形式发布的确切代码复制它。您是否熟悉基本的 HTTP 以传递请求参数、cookie 等?在 Chrome 中按 F12 并单击 Network 选项卡以查看它。它应该提供有关问题的线索(例如缺少会话 cookie)。

以上是关于使用 JSF 2.2 时在每个回发请求上重新创建 @ViewScoped bean的主要内容,如果未能解决你的问题,请参考以下文章

JSF 2.2 ViewScoped Bean 被多次创建

在每个 ajax 请求上重建 JSF 视图

在每次 JSF ajax 回发后执行 JavaScript

为啥 JSF 2.2 需要更多时间在 Wildfly 上部分呈现 ajax 请求

(RC 4.3.4)中的rich:fileUpload 组件在Apache Tomcat7 和JSF 2.2 上工作吗? :“无法读取请求序言”

@ViewScoped 在每个回发请求上调用 @PostConstruct