3

JSF 2、Spring、および Hibernate を使用してアプリケーションを構築しています。MyFaces Orchestra は、アプリケーションのほとんどのページで使用している会話スコープを提供するために使用されています (Hibernate セッションの Orchestra の管理を利用するため)。すべての Bean は conversation.access スコープを使用するように宣言されています。これは、(Orchestrator のドキュメントによると) ユーザーがそのバッキング Bean インスタンスへの参照を含まないページに移動するとすぐに、Bean がスコープから削除されることを意味するはずです。 .

私が遭遇している問題は、会話を明示的に無効にせずにビューから道をナビゲートした場合、後でそのビューに戻った場合でも、以前と同じデータが残っていることです。すべてのバッキング Bean に ConversationBindingListener メソッドを実装しましたが、それらがいつ会話から削除されるかを確認でき、多くの場合、そうではないことがわかります。

問題をさらに複雑にしているのは、一部のページ (ビュー) に移動するとバッキング Bean が削除され、他のページには移動しないことです。おそらく、EL 内の他のバッキング Bean への意図しない参照がページにあったためだと思いましたが、何も見つかりませんでした。また、この問題は、conversation.access スコープ Bean を持つ 1 つのページから、別の conversation.scoped Bean を使用する別のページに移動したときにのみ発生したのではないかと考えました。ただし、会話から削除された場合、そのページには conversation.access スコープ Bean への参照も含まれます。

先に述べたように、Conversation.getCurrentInstance().invalidate() を使用して会話を明示的に無効にすることは機能します。ただし、ユーザーがナビゲーション リンクの 1 つをクリックするだけでビューを離れることができるという非常に一般的なユース ケースであるため、すべてのユース ケースで会話を明示的に無効にすることはできません。

追加の詳細: Hibernate 3.6 (JPA の代わりに) を使用しているため、HibernatePersistenceContextFactoryを使用する必要がありました。

  • MyFaces オーケストラ (myfaces-orchestra-core20-1.4.jar)
  • JSF 2 (モハラ 2.0.4)
  • スプリング 3.0
  • プライムフェイス 2.2.1
  • リッチフェイス 4.0.0

これが私の Spring コンテキスト構成の外観です (オーケストラの場合)。

<!-- 1. initialization of all orchestra modules (required for core15 module) -->
<import resource="classpath*:/META-INF/spring-orchestra-init.xml" />

<!-- 2. the conversation scopes -->
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="conversation.manual">
                <bean
                    class="org.apache.myfaces.orchestra.conversation.spring.SpringConversationScope">
                    <property name="timeout" value="30" />
                    <property name="advices">
                        <list>
                            <ref bean="persistentContextConversationInterceptor" />
                        </list>
                    </property>
                </bean>
            </entry>
            <entry key="conversation.access">
                <bean
                    class="org.apache.myfaces.orchestra.conversation.spring.SpringConversationScope">
                    <property name="timeout" value="30" />
                    <property name="advices">
                        <list>
                            <ref bean="persistentContextConversationInterceptor" />
                        </list>
                    </property>
                    <property name="lifetime" value="access" />
                </bean>
            </entry>
        </map>
    </property>
 </bean>    


<!-- 3. the "entity manager" manager -->
<bean id="persistentContextConversationInterceptor"
    class="org.apache.myfaces.orchestra.conversation.spring.PersistenceContextConversationInterceptor">
    <property name="persistenceContextFactory" ref="persistentContextFactory" />
</bean>



<!-- 4. conversation - persistence adapter -->
<bean id="persistentContextFactory"
    class="com.acme.infra.orchestra.hibernate.HibernatePersistenceContextFactory">
    <property name="entityManagerFactory" ref="sessionFactory" />
</bean>

<!-- 5. persistence -->
<bean id="managedDataSource"
    class="org.apache.myfaces.orchestra.connectionManager.ConnectionManagerDataSource">
    <property name="dataSource" ref="dataSource" />
</bean>

JSF バッキング Bean 宣言の例をいくつか示します。

<bean id="quoteSummaryBackingBean" class="com.acme.ui.backing.QuoteSummaryBackingBean"
        scope="conversation.access" orchestra:conversationName="QuoteSummaryConversation">
    <property name="quotingBusinessService" ref="quotingBusinessService"/>
    <property name="customerBusinessService" ref="customerBusinessService"/>
    <property name="referenceDataBusinessService" ref="referenceDataBusinessService"/>
    <property name="quoteExportBusinessService" ref="quoteExportBusinessService" />
</bean>

<bean id="createQuoteBackingBean" class="com.acme.ui.backing.CreateQuoteBackingBean" 
        scope="conversation.access" orchestra:conversationName="CreateQuoteConversation">  
    <property name="quotingBusinessService" ref="quotingBusinessService"/>
    <property name="customerBusinessService" ref="customerBusinessService"/>
    <property name="referenceDataBusinessService" ref="referenceDataBusinessService"/>


4

2 に答える 2

2

これは最も洗練された解決策ではなく、新しいバグが発生する可能性があると推測しています (Orchestrator で使用されるチェックは AJAX リクエストの状況を処理することを意図していたためです)。org.apache.myfaces.orchestra.conversation.jsf.AccessScopePhaseListener:oldView リクエスト スコープ変数を null にリセットする新しいメソッドを (基本クラスを使用して) バッキング Bean に追加しました。

public void clearPreviousConversation() {
    if (firstHit) {
        String keyName = 
            "org.apache.myfaces.orchestra.conversation.jsf.AccessScopePhaseListener:oldView";

        FacesContext.getCurrentInstance().getExternalContext()
        .getRequestMap().put(keyName, null);

        firstHit = false;
    }
}   

このメソッドがビューごとに 1 回だけ呼び出されるようにするために、boolean メンバー変数である「firstHit」フラグがあります。

次に、この特定の問題は f:metadata を使用するビューでのみ現れるため、この事実を利用して、必要な場所でのみこのメソッドを呼び出します。f:metadata に pre-render 呼び出しとして追加します。

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

f:viewParam またはその他の f:event 要素を使用している場合は、それらを混在させることができます。

<f:metadata>
    <f:viewParam name="tabIndex" value="#{controlBackingBean.tabIndex}" />
    <f:event type="preRenderView" listener="#{controlPanelBackingBean.clearPreviousConversation}" />
    <f:event type="preRenderView" listener="#{controlPanelBackingBean.init}" />
</f:metadata>
于 2011-07-07T03:49:50.600 に答える