在每个请求中调用ConversationScoped bean的PostConstruct方法

时间:2015-10-18 22:29:40

标签: jsf cdi conversation-scope

好吧,我正在使用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被存储在会话中以供之后使用。我有一个commandButton" save"在我的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>

所以,我理解&#34; href =#&#34;避免执行onlick。我认为这是问题,但我不知道如何解决。 Remenber:从不调用salvarAndRedirecionar()方法,因为之前总是调用postConstruct。

2)我有另一个问题:如果我开始谈话并且不会结束,那么会有一些问题吗?有时我不想手动结束对话,因为我只有一页,我才开始。

1 个答案:

答案 0 :(得分:4)

您遇到此问题的原因是您正在调用会话范围bean的postconstruct方法中调用conversation begin方法。因此,会话将在渲染响应阶段设置为长时间运行状态,而不是在渲染响应阶段之前。问题是CID参数是在HTML表单元素上呈现的,但此时会话仍然处于临时状态,因为在请求之后仍未调用postconstruct方法。重新命名commandLink元素时调用postconstruct方法,然后为时已晚,HTML表单元素不会带有CID参数:

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

因此,解决方案包括将对话开始移动到渲染响应阶段之前的某个点。如果您使用的是JSF 2.2,则可以使用f:viewAction标记;如果您使用的是旧版本,则可以使用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。