【问题标题】:ViewScoped bean getting constructed on every request... part 99 [duplicate]ViewScoped bean 在每个请求上构建...第 99 部分 [重复]
【发布时间】:2011-11-18 23:26:00
【问题描述】:

啊...这似乎有一百个答案,我还没有找到适合我的答案,所以我想我真的会再问一次。这是我的场景:

从技术上讲,我的网站只有一个页面,其内容被换出,而不是您导航到的多个页面。起点是这个块:

<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head />
  <h:body>
    <ui:include src="resourceInclude.xhtml" />
    <ui:include src="main.xhtml" />
  </h:body>
</f:view>

resourceInclude.xhtml 包含我的 css 文件:

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:outputStylesheet library="css" name="test.css" target="head" />
</ui:composition>

而 main.xhtml 是视图:

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html">
  <h:panelGroup styleClass="test-container" layout="block">
    <h:form id="main-form">
      <h:panelGroup styleClass="test-header" layout="block">
        <h:panelGroup styleClass="navigation" layout="block">
          <ul>
            <li><h:commandLink action="#{viewSelector.setModeHome}">
                <h:outputText value="Home" />
              </h:commandLink></li>
            <li><h:commandLink action="#{viewSelector.setModeReports}">
                <h:outputText value="ASAP Reports" />
              </h:commandLink></li>
            <li><h:commandLink action="#{viewSelector.setModeSupport}">
                <h:outputText value="Technical Support" />
              </h:commandLink></li>
            <li><h:commandLink action="#{viewSelector.setModeHelp}">
                <h:outputText value="Help" />
              </h:commandLink></li>
          </ul>
        </h:panelGroup>
      </h:panelGroup>
      <h:panelGroup styleClass="test-content" layout="block">
        <ui:include src="#{viewSelector.modeName}-view.xhtml" />
      </h:panelGroup>
      <h:panelGroup styleClass="test-footer" layout="block">
        <h:messages />
      </h:panelGroup>
    </h:form>
  </h:panelGroup>
</ui:composition>

它由三个h:panelGroups 组成。第一个是一组四个通用导航链接,每个链接都会更改viewSelector.modeName 值,该值用于包含第二个h:panelGroup 中的内容,因此&lt;ui:include src="#{viewSelector.modeName}-view.xhtml" /&gt;。我已经为这个例子去掉了这个,所以每个视图基本上都是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html">
  <h:panelGroup styleClass="test-home-view">
    <p>home</p>
  </h:panelGroup>
</ui:composition>

第三个h:panelGroup 是所有消息的页脚,用于调试问题所在。

无论如何,每次我单击导航链接之一时,都会调用 viewSelector bean 的构造函数。这是我的 viewSelector bean 的样子:

package org.mitre.asias.aires.controller;


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


import org.apache.log4j.Logger;


@ManagedBean( name="viewSelector" )
@ViewScoped
public class ViewSelector {
    protected static Logger log = Logger.getLogger( ViewSelector.class );
    private Mode mode = Mode.HOME;
    public static final String PORTLET_NAME = "Test";

    public static enum Mode {
        HOME(1, "home"),
        REPORTS(2, "reports"),
        SUPPORT(3, "support"),
        HELP(4, "help");

        private int value;
        private String name;

        private Mode( int value, String name ) {
            this.value = value;
            this.name = name;
        }

        public int getValue() {
            return value;
        }

        public String getName() {
            return name;
        }
    }

    public ViewSelector() {
        log.trace( "constructing new ViewSelector" );
    }

    public Mode getMode() {
        log.trace( "getting mode" );

        return mode;
    }

    public String getModeName() {
        log.debug( "in getmodename" );
        return getMode().getName();
    }

    public String getPortletName() {
        return PORTLET_NAME;
    }

    public boolean isModeReports() {
        return getMode() == Mode.REPORTS;
    }

    public void setMode( Mode mode ) {
        this.mode = mode;
    }

    public void setModeHelp() {
        setMode( Mode.HELP );
    }

    public void setModeHome() {
        setMode( mode = Mode.HOME );
    }

    public void setModeReports() {
        setMode( mode = Mode.REPORTS );
    }

    public void setModeSupport() {
        setMode( mode = Mode.SUPPORT );
    }
}

我知道我一定是以错误的方式做某事,否则我错过了关于 JSF 如何工作的核心内容。任何输入?

【问题讨论】:

    标签: jsf jsf-2 lifecycle view-scope postconstruct


    【解决方案1】:

    &lt;ui:include src&gt; 中的 EL 导致了这种情况。

    如果不能按照issue 1492 禁用web.xml 中的部分状态保存,则

    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>true</param-value>
    </context-param>
    

    那么你需要更换

    <ui:include src="#{viewSelector.modeName}-view.xhtml" />
    

    类似

    <h:panelGroup rendered="#{viewSelector.mode == 'HOME'}">
        <ui:include src="home-view.xhtml" />
    </h:panelGroup>
    <h:panelGroup rendered="#{viewSelector.mode == 'REPORTS'}">
        <ui:include src="reports-view.xhtml" />
    </h:panelGroup>
    <h:panelGroup rendered="#{viewSelector.mode == 'SUPPORT'}">
        <ui:include src="support-view.xhtml" />
    </h:panelGroup>
    <h:panelGroup rendered="#{viewSelector.mode == 'HELP'}">
        <ui:include src="help-view.xhtml" />
    </h:panelGroup>
    

    类似的问题之前至少被问过一次:)

    【讨论】:

    • 再次感谢。你已经厌倦了听到这个:)。任何ui 元素中的EL 是否会导致这种情况,或者只是ui:include?换句话说,如果我改用模板,我还会遇到这个问题吗?哦,我保证下次会做更多的搜索......
    • 虽然很难找到,对我来说也是如此 :) 幸运的是我回忆了这个主题,这样我就可以更容易地找到它。至于问题,只有当您通过 EL 将任何 标记处理程序 的属性绑定到视图范围 bean 时,才会发生这种情况。标记处理程序在视图构建时间而不是视图渲染时间运行。标签处理程序都是 JSTL &lt;c:xxx&gt; 标签,一些 JSF &lt;f:xxx&gt; 标签和一些 Facelets &lt;ui:xxx&gt; 标签。在这个(相关)博客中,您可以在一张漂亮的表格中找到它们:ninthavenue.com.au/blog/c:foreach-vs-ui:repeat-in-facelets
    • 巧合的是,上周我正忙着写一篇“JSF 2.0 中的通信”博客文章,我刚刚在一个小时前发布了这篇文章。有一章更详细地处理了这个特殊问题:balusc.blogspot.com/2011/09/…
    • 我用h:panelGroup rendered="#{el}" 切换到你的建议,但是有一个问题。我的第二部分也有 4 种模式,其中一种是活动模式。其中,第 4 模式依赖于在第 3 模式中设置的变量,并且只能从第 3 模式导航到。但是,rendered 似乎并没有阻止ui:include 包含该页面。这是有道理的,因为 ui:include 被处理以构建页面,而 rendered 只会在渲染期间被检查。有没有办法防止ui:include
    • 这确实是这个鸡蛋问题的尴尬副作用:/禁用部分状态保存不是一个选项吗?理论上,这可以通过@CustomScoped 解决,它将视图范围的bean 直接保存在会话范围而不是视图状态中。如果那天晚些时候我有时间,我会尝试一下。
    猜你喜欢
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2013-12-13
    • 2012-10-16
    • 2015-01-14
    • 2011-02-20
    • 2014-10-17
    • 1970-01-01
    相关资源
    最近更新 更多