1

好吧,我正在使用 ConversationScoped,我希望 PostConstruct 在对话开始时只被调用一次,请参阅:

@Named("disciplinaDetalheMB")
@ConversationScoped
public class DisciplinaDetalheMBImpl {

    private static final long serialVersionUID = 1L;

    @Inject
        private Conversation conversation;

    @Inject
    @AnBasicBO
    private BasicBO boPadrao;

@PostConstruct
    public void postConstruct() {
    logger.debug("Iniciando PostConstruct...");
    init();
    beginConversation();
    }

public String salvarAndRedirecionar() {
    salvar();
    if (!FacesContext.getCurrentInstance().isValidationFailed()) {
        return goToLastPage() + "?faces-redirect=true";
    } else {
        return "";
    }
    }


private void beginConversation() {
    if (!conversation.isTransient()) {
        endConversation();
    }
    conversation.begin();
    if (conversation.isTransient()) {
        throw new RuntimeException("A conversão não foi iniciada corretamente");
    }
    SessionContext.getInstance().setAttribute("cid", conversation.getId());

    }

    public BasicBO getBoPadrao() {
        return boPadrao;
    }

    public void setBoPadrao(BasicBO boPadrao) {
        this.boPadrao = boPadrao;
    }

}

因此,当创建我的支持 bean 时,会话被初始化,CID 存储在会话中以供以后使用。我的 XHTML 中有一个命令按钮“保存”,当调用此按钮时,再次调用 PostConstruct,我不知道为什么:

<h:commandLink
            action="#{managedBeanName.salvarAndRedirecionar()}"
            styleClass="btn btn-info pull-right" value="Salvar">
            <f:ajax execute="@form" />
        </h:commandLink>

我注意到生成的 HTML 是:

<a id="formManterDisciplina:j_idt44:j_idt46" href="#" onclick="mojarra.ab(this,event,'action','@form',0);return false" class="btn btn-info pull-right" name="formManterDisciplina:j_idt44:j_idt46">Salvar</a>

所以,我理解“href=#”避免了onlick被执行。我认为这是问题所在,但我不知道如何解决。记住:salvarAndRedirecionar() 方法永远不会被调用,因为 postConstruct 总是在之前被调用。

2)我还有一个问题:如果我开始对话但没有结束,有什么问题吗?有时我不想手动结束对话,因为我只有一页,我才开始。

4

1 回答 1

4

您遇到此问题的原因是您在对话范围 bean 的 postconstruct 方法中调用了对话开始方法。因此,对话将在渲染响应阶段而不是之前设置为长时间运行状态。问题是 CID 参数是在 HTML 表单元素上渲染的,但此时会话仍处于瞬态,因为请求后仍未调用 postconstruct 方法。postconstruct 方法在重新渲染 commandLink 元素时被调用,然后就来不及了,HTML 表单元素不会携带 CID 参数:

<form id="yourForm" name="yourForm" method="post" action="/path/to/yourPage.xhtml" enctype="application/x-www-form-urlencoded">

因此,解决方案包括将对话开始移动到呈现响应阶段之前的某个点。f:viewAction如果您使用的是 JSF 2.2,则可以使用标记来执行此操作;f:event如果您使用的是旧版本,则可以使用标记。

然后您将看到在 HTML 表单元素中呈现的 CID 参数,如下所示:

<form id="yourForm" name="yourForm" method="post" action="/path/to/yourPage.xhtml?cid=1" enctype="application/x-www-form-urlencoded">

  • 如果您使用f:event标签:

在您的页面中:

<f:metadata>
    <f:event listener="#{disciplinaDetalheMB.initConversation}" type="preRenderView" /> 
</f:metadata>

在您的支持 bean 中:

public void initConversation(){
    if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
          conversation.begin();
    }
}
  • 如果您使用f:viewAction标签:

在您的页面中:

<f:metadata>
    <f:viewAction action="#{disciplinaDetalheMB.initConversation}" />
</f:metadata>

在您的支持 bean 中:

public void initConversation(){
    if (conversation.isTransient()) {
          conversation.begin();
    }
}

关于你的第二个问题,不结束对话没有什么大问题,因为它有一个像 HTTP 会话一样的超时。您可以根据您的服务器资源管理策略和空闲会话所需的生命周期来设置超时值。无论如何,当您只有一个页面时,您最好使用视图范围的支持 bean。

于 2015-10-19T21:31:23.153 回答