java - 在请求范围内动态呈现 JSF 2 内容 - 在动态内容中时不会调用监听器

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

我已将我的问题案例放在下面,这简化了我遇到的现实问题。通过将 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()} 监听器永远不会触发

最佳答案

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

要解决您的特定问题,您所需要做的就是使用 @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 .

另请参阅:

关于java - 在请求范围内动态呈现 JSF 2 内容 - 在动态内容中时不会调用监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8883551/

相关文章:

java - 如何启用Camel NettyChannelBufferStreamCache类型转换?

java - 在 Eclipse 中排除 JUnit 测试

java - 在 bean 中下载 JSF CSV

ajax - primefaces 模板 ajax 状态

javascript - setStyleClass 方法覆盖已经定义的 styleClass

java - <f :setPropertyActionListener . ../> 不起作用

java - 在 richfaces 中使用自定义 skin.properties 文件时无法找到 skinning.css 和 packed.css

java - Spring事务性包私有(private)方法

java - JUnit 测试 - 进行测试的最佳且最可靠的方法?

jsf-2 - JSF 复合组件 - 尝试保存状态时的奇怪行为