7

說有一個用戶表結構:如何啓用sessionFactory.getCurrentSession休眠濾波器()?

用戶

  • 列表項
  • 用戶ID(PK)
  • 公司(PK)
  • 的userName
  • 地址.. .etc

我想只爲當前公司檢索用戶(公司可以通過用戶界面更改公司,所以公司是運行時參數)

類似地,還有許多其他表具有與普通列相似的結構公司),我想限制數據只有當前的公司,所以我使用休眠過濾器來過濾數據。

Hibernate的註解:

<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 

    <property name="dataSource"> 
     <ref bean="dataSource" /> 
    </property> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">Dialect....</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.generate_statistics">true</prop> 
      <prop key="hibernate.connection.release_mode">after_transaction</prop> 
      <prop key="hibernate.cache.use_second_level_cache">false</prop> 
     </props> 
    </property> 
    <property name="annotatedClasses"> 
     <list> 
      <value>User</value> 
     ..... 
     </list> 
    </property> 
</bean> 

過濾器定義:

 
@org.hibernate.annotations.FilterDef(name="restrictToCurrentCompany", 
    parameters = {@org.hibernate.annotations.ParamDef(
      name = "currentCompanyNumber", type = "int" 
     ) 
    } 
) 
@Entity 
@Table(name = "USER") 
@org.hibernate.annotations.Filter(
     name = "restrictToCurrentCompany", 
     condition="company = :currentCompanyNumber" 
) 
public class User implements Serializable { 
    private int company; 
    private String userName; 
    ...etc.. 
} 

道的:

 

@Repository 
@Transactional(readOnly = true) 
public class UserDAOImpl implements UserDAO { 

    @Autowired(required = true) 
    private SessionFactory sessionFactory; 

    public Set getUsers(){ 
     .....Criteria queries to retrieve users for the current company  
    } 

    private Session getSession(){ 
     return sessionFactory.getCurrentSession(); 
    } 

} 

如果我改變,像這樣的getSession;

private Session getSession(){ 
    Session session = sessionFactory.getCurrentSession(); 
    Filter filter = session.enableFilter("restrictToCurrentCompany"); 
    filter.setParameter("currentCompanyNumber", UserUtils.getCurrentCompany()); 
    return sessionFactory.getCurrentSession(); 
} 

那麼我就可以啓用過濾器,一切看起來不錯,但不是讓會議期間啓用過濾器是有一個申請,使整個會話工廠/應用層過濾簡單的替代方案?如果是這樣,我怎麼能使用彈簧配置呢?我試圖掛鉤入休眠攔截器(預加載事件listerns),但我有點不確定這是一種正確的方法,還是應該使用上面列出的getSession方法來啓用過濾器?

+0

你最終什麼了起來做,@sachink?同樣,我想自動設置我的運行時篩選器的值不那麼突兀的方式。 – 2013-02-28 18:58:50

回答

14

你的解決方案是非常簡單的,但我猜你正在嘗試的就是讓這個你不必提供在每個你的DAO的「的getSession」執行。最終,您的實現方法將取決於您希望如何使用此過濾器。以下兩種方式可以解決這個問題。

最簡單的方法是簡單地讓你在UserDAOImpl延長包含在裏面了「的getSession」邏輯新的基類。這種方法將允許你減少代碼中,你將不得不在大多數情況下應用這個過濾器的邏輯,但是當你需要,你可以覆蓋過濾。

您可以創建這樣的事情:

public class BaseDAO 
{ 

    // ... possibly some other methods and variables 

    @Autowired(required = true) 
    private SessionFactory sessionFactory; 

    protected Session getSession() 
    { 
     //Your session filter logic above 
    } 
} 

現在你可以只是你在UserDAOImpl子類這一點,並得到一個會話時,它需要做一些事情。這是一種非常簡單的方式來做你正在尋找的東西,但它不是萬無一失的。如果你正在寫一個框架,供他人使用,那麼你會從簡單的通過具有春天注入它讓自己的參考SessionFactory的阻止他們,然後他們可以得到一個未經過濾的會議?在某些情況下,您可能需要這樣做的行政流程可以對全部數據採取行動,但我將描述的下一個方法應該防止發生這種情況。

解決此問題的第二種方法涉及使用AOP將SessionFactory的getSession方法與您的邏輯進行封裝,以在會話返回之前應用過濾器。這個方法意味着即使有人獲得了你自己的SessionFactory的引用,他們仍然會應用這個過濾邏輯。

首先,如果你不熟悉春季AOP,請看參考文獻http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html。我將使用基於模式的方法將建議應用於Hibernate,因爲我們不想修改Hibernate的源代碼。 ;)你可以在http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-schema找到這個方法的細節。

首先,確保你有以下模式和AOP:配置部分在您的應用程序上下文XML春天:

<?xml version="1.0" encoding="UTF-8"?> 
<beans ... 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation=" 
     ... 
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 

    ... 

<aop:config> 
    <aop:aspect id="forceFilter" ref="sessionFilterAdvice"> 
     <aop:pointcut id="hibernateSessionFactoryGetSession" 
      expression="execution(* org.hibernate.SessionFactory.openSession(..))" /> 
     <aop:after-returning method="setupFilter" 
      pointcut-ref="hibernateSessionFactoryGetSession" returning="session" /> 
    </aop:aspect> 
</aop:config> 

    ... 
</beans> 

接下來,你需要一個bean添加到項目實施sessionFilterAdvice豆我們在上面引用aop:aspect標籤。創建下面的類:

package net.grogscave.example; 

import org.hibernate.Filter; 
import org.hibernate.Session; 
import org.springframework.stereotype.Service; 

@Service 
public class SessionFilterAdvice 
{ 
    public void setupFilter(Session session) 
    { 
     Session session = sessionFactory.getCurrentSession(); 
     Filter filter = session.enableFilter("restrictToCurrentCompany"); 
     filter.setParameter("currentCompanyNumber", UserUtils.getCurrentCompany()); 
    } 
} 

的最後一件事,以確保的是,你的項目包括彈簧AOP罐子和aspectjweaver罐子。我不知道你是否使用了依賴管理,但是你需要將這些jar放到你的項目類路徑中。

您現在應該可以重新編譯您的項目,並且現在對實現SessionFactory的類的任何openSession方法的任何調用都會將您的過濾器添加到它們。

1

Hibernate hbm文件: 在您的hbm文件中聲明過濾器。這裏filterByFacilityIDs是一個過濾器,facilityIDsParam是一個List < String> type參數。

<hibernate-mapping package="com.ABC.dvo"> 
<class name="ItemMasterDVO" table="Item_Master"> 
    .... 
<set name="inventoryTaxesSet" inverse="true" cascade="all"> 
<key column="item_ID" /> 
<one-to-many class="InventoryTaxesDVO" /> 
    <filter name="filterByFacilityIDs" condition="Facility_ID in(:facilityIDsParam)"/> 
</set> 
</class> 
<filter-def name="filterByFacilityIDs"> 
<filter-param name="facilityIDsParam" type="string"/> 
</filter-def> 
</hibernate-mapping> 

** Java類**

public List<ItemMasterDVO> getItemMaster(String[] itemIDs, String[] facilityIDs){ 
    Session session = getSessionFactory().getCurrentSession(); 
    Criteria criteria = session.createCriteria(ItemMasterDVO.class) 
     .add(Restrictions.in("itemNumber", itemIDs)) 
     .setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 
    if(facilityIDs!=null && facilityIDs.length>0){   
     org.hibernate.Filter filter = session.enableFilter("filterByFacilityIDs"); 
     filter.setParameterList("facilityIDsParam", facilityIDs); 
    } 
    criteria.addOrder(Order.asc("itemNumber")); 
    List<ItemMasterDVO> result = criteria.list(); 
    return result; 
    }