【问题标题】:Dynamically rendered JSF 2 content in request scoped - listener not called when in dynamic content在请求范围内动态呈现 JSF 2 内容 - 在动态内容中未调用侦听器
【发布时间】:2012-02-11 14:28:38
【问题描述】:

我将我的问题案例放在下面,这简化了我遇到的现实问题。通过将 Bean 更改为 @SessionScoped 我可以解决这个问题,但这确实是不可取的。就像@ViewScoped 一样。我认为它应该在@RequestScoped 中工作。我的问题是:

  • 为什么 JSF 需要访问 #{simpleBean.outerStrings} 才能调用 #{simpleBean.processInnerClick()} 侦听器(outerStrings 将在上一个请求中死亡)
  • 解决此问题的最佳模式是什么?

很高兴编辑以使其更清晰 - 请告诉我。

Bean 类

import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class SimpleBean implements Serializable {

    private List<String> topLevelStrings = 
               Arrays.asList("TopLevel1", "TopLevel2");

    private List<String> outerStrings;

    private List<String> innerStrings;

    public void processOuterClick() {
        System.err.println("processOuterClick()");
        outerStrings = Arrays.asList("Outer1", "Outer2", "Outer3");
    }

    public void processInnerClick() {
        System.err.println("processInnerClick()");
        innerStrings = Arrays.asList("InnerA", "InnerB", "InnerC");
    }

    public List<String> getOuterStrings() {
        return outerStrings;
    }

    public List<String> getInnerStrings() {
        return innerStrings;
    }

    public List<String> getTopLevelStrings() {
        return topLevelStrings;
    }

}

XHTML

<h:form>
<ui:repeat var="toplevel" value="#{simpleBean.topLevelStrings}"
           id="toplevel_id">
<h:commandLink id="toplevel_command">
#{toplevel} <br/>
<f:ajax render="outerlevel_panel" 
        listener="#{simpleBean.processOuterClick()}"/>
</h:commandLink>
<h:panelGroup id="outerlevel_panel">
<ui:repeat var="outerLevel" value="#{simpleBean.outerStrings}" 
    id="outerlevel_id">
<h:commandLink id="outerlevel_command">
#{outerLevel} <br/> 
<f:ajax listener="#{simpleBean.processInnerClick()}" render="innerlevel_panel"/>                   
</h:commandLink>                            
<h:panelGroup id="innerlevel_panel">
<ui:repeat var="innerLevel" value="#{simpleBean.innerStrings}" 
           id="innerlevel_id">
<h:commandLink id="innerlevel_command">
#{innerLevel} <br/>        
</h:commandLink>
</ui:repeat>
</h:panelGroup>
</ui:repeat>
</h:panelGroup>         
</ui:repeat>
</h:form>

基本上:

  • #{simpleBean.processOuterClick()} 侦听器触发正常,#{outerLevel} 命令链接呈现
  • 但是当我点击#{outerLevel} 命令链接时,#{simpleBean.processInnerClick()} 监听器永远不会被触发

【问题讨论】:

    标签: java jsf jsf-2 java-ee-6 myfaces


    【解决方案1】:

    请求范围是此特定要求的错误范围。请求范围的 bean 在响应结束时被丢弃,并且将在后续请求中创建一个新的 bean,并将其所有属性设置为默认值。在 JSF2 术语中,您确实需要视图范围。对于此要求,会话范围确实比请求范围太宽且更糟糕(当最终用户在多个窗口/选项卡中打开同一页面时,他们将在物理上共享同一个 bean,从而导致不直观的每次查看行为)最终用户在交互后在视图之间切换)。

    您只需使用@ManagedBean @ViewScoped 即可解决您的特定问题:

    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    
    @ManagedBean
    @ViewScoped
    public class SimpleBean implements Serializable {
        // ...
    }
    

    由于某种原因,您似乎更喜欢 CDI 管理而不是 JSF 管理,所以 @ViewScoped 的 CDI 替代品是 @ConversationScoped

    import javax.enterprise.context.Conversation;
    import javax.enterprise.context.ConversationScoped;
    import javax.inject.Named;
    
    @Named
    @ConversationScoped
    public class SimpleBean implements Serializable {
    
        @Inject
        private Conversation conversation;
    
        @PostConstruct
        public void init() {
            conversation.begin();
        }
    
        public String navigateToOtherPage() {
            conversation.end();
            return "otherPage?faces-redirect=true";
        }
    
        // ...
    }
    

    您只需管理对话的开始和结束yourself

    另见:

    【讨论】:

    • 感谢您的回复 - 但是为什么 Jsf 需要访问 outerStrings?内部点击的监听器没有引用它,我也没有要求 Ajax 调用评估使用 outerStrings 进行渲染的组件(至少直接)
    • 它需要它才能找到与动作关联的组件,以便可以调用它。另请参阅第一个“另请参阅”链接。另一种方法是使用&lt;f:param&gt; 来传递请求参数并在(后)构造函数中准确准备所需的模型。另见stackoverflow.com/questions/4994458/…
    • 哦,好的,我明白了。谢谢。像这样的问题,我认为 jsf 不太适合 - 它有组件树,我只想渲染一个新组件,而不是检查原始视图渲染时使用的模型数据是否仍然存在。最终结果是,我只希望在 DOM 中的数据必须比我希望在服务器上的寿命更长。
    • 您不应将 JSF 视图状态与 HTML DOM 树混淆。
    • 嗯。那么在一个基于动作的框架中,我将只使用 Ajax 调用服务器,评估 JSP 并将输出发送回。然后我会将内容附加到我的 dom 元素中。对于我的要求,这就是我希望 jsf 做的事情 - 我不希望 Ajax 调用需要服务器上以前使用的整个数据集
    猜你喜欢
    • 2015-01-19
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 2022-08-07
    • 2019-07-30
    • 1970-01-01
    相关资源
    最近更新 更多