2013-04-01 32 views

回答

2

OSIVFilter必須高於WicketFilter,否則請求將無法達到它。 WicketFilter本身處理頁面請求,它不委託給其他組件,比如另一個servlet(因此,過濾器鏈停在那裏)。

另一種方法是創建一個與OSIVFilter相同的IRequestCycleListener的實現。我已經通過修改Spring的過濾器的代碼以符合新的界面,如下圖創造了這樣的類:

import org.apache.wicket.MetaDataKey; 
import org.apache.wicket.protocol.http.WebApplication; 
import org.apache.wicket.request.cycle.AbstractRequestCycleListener; 
import org.apache.wicket.request.cycle.RequestCycle; 
import org.hibernate.FlushMode; 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.dao.DataAccessResourceFailureException; 
import org.springframework.orm.hibernate4.SessionFactoryUtils; 
import org.springframework.orm.hibernate4.SessionHolder; 
import org.springframework.transaction.support.TransactionSynchronizationManager; 
import org.springframework.web.context.WebApplicationContext; 
import org.springframework.web.context.support.WebApplicationContextUtils; 

public class OpenSessionInViewRequestCycleListener extends AbstractRequestCycleListener { 

    protected final Logger logger = LoggerFactory.getLogger(getClass()); 

    public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory"; 

    private static final MetaDataKey<Boolean> PARTICIPATE = new MetaDataKey<Boolean>() { 
    }; 

    private static final MetaDataKey<SessionFactory> SESSION_FACTORY = new MetaDataKey<SessionFactory>() { 
    }; 

    private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME; 

    private final WebApplication application; 

    public OpenSessionInViewRequestCycleListener(WebApplication application) { 
     this.application = application; 
    } 

    /** 
    * Set the bean name of the SessionFactory to fetch from Spring's 
    * root application context. Default is "sessionFactory". 
    * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME 
    */ 
    public void setSessionFactoryBeanName(String sessionFactoryBeanName) { 
     this.sessionFactoryBeanName = sessionFactoryBeanName; 
    } 

    /** 
    * Return the bean name of the SessionFactory to fetch from Spring's 
    * root application context. 
    */ 
    protected String getSessionFactoryBeanName() { 
     return this.sessionFactoryBeanName; 
    } 

    @Override 
    public void onBeginRequest(RequestCycle cycle) { 
     SessionFactory sessionFactory = lookupSessionFactory(cycle); 
     cycle.setMetaData(SESSION_FACTORY, sessionFactory); 
     cycle.setMetaData(PARTICIPATE, false); 

     if (TransactionSynchronizationManager.hasResource(sessionFactory)) { 
      // Do not modify the Session: just set the participate flag. 
      cycle.setMetaData(PARTICIPATE, true); 
     } 
     else { 
      logger.debug("Opening Hibernate Session in OpenSessionInViewRequestCycleListener"); 
      Session session = openSession(sessionFactory); 
      SessionHolder sessionHolder = new SessionHolder(session); 
      TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); 
     } 
    } 

    @Override 
    public void onEndRequest(RequestCycle cycle) { 
     if (!cycle.getMetaData(PARTICIPATE)) { 
      SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(cycle.getMetaData(SESSION_FACTORY)); 
      logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 
      SessionFactoryUtils.closeSession(sessionHolder.getSession()); 
     } 
    } 

    /** 
    * Look up the SessionFactory that this filter should use, 
    * taking the current HTTP request as argument. 
    * <p>The default implementation delegates to the {@link #lookupSessionFactory()} 
    * variant without arguments. 
    * @param cycle the current request 
    * @return the SessionFactory to use 
    */ 
    protected SessionFactory lookupSessionFactory(RequestCycle cycle) { 
     return lookupSessionFactory(); 
    } 

    /** 
    * Look up the SessionFactory that this filter should use. 
    * <p>The default implementation looks for a bean with the specified name 
    * in Spring's root application context. 
    * @return the SessionFactory to use 
    * @see #getSessionFactoryBeanName 
    */ 
    protected SessionFactory lookupSessionFactory() { 
     if (logger.isDebugEnabled()) { 
      logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter"); 
     } 
     WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(this.application.getServletContext()); 
     return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class); 
    } 

    /** 
    * Open a Session for the SessionFactory that this filter uses. 
    * <p>The default implementation delegates to the 
    * {@code SessionFactory.openSession} method and 
    * sets the {@code Session}'s flush mode to "MANUAL". 
    * @param sessionFactory the SessionFactory that this filter uses 
    * @return the Session to use 
    * @throws DataAccessResourceFailureException if the Session could not be created 
    * @see org.hibernate.FlushMode#MANUAL 
    */ 
    protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { 
     try { 
      Session session = sessionFactory.openSession(); 
      session.setFlushMode(FlushMode.MANUAL); 
      return session; 
     } catch (HibernateException ex) { 
      throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); 
     } 
    } 

} 
+0

把解決問題,以在servlet的web.xml Wicket的過濾器上面的OSIV過濾器。 –

+0

它可以工作,但有一個缺點:如果OSIVFilter引發異常,用戶將看到Tomcat的錯誤頁面,而不是Wicket的錯誤頁面。這可能是一個問題或不是。 – tetsuo

相關問題