【问题标题】:How to enable hibernate filter for sessionFactory.getCurrentSession()?如何为 sessionFactory.getCurrentSession() 启用休眠过滤器?
【发布时间】:2011-08-06 13:10:33
【问题描述】:

假设有一个具有结构的用户表:

用户

  • 列表项
  • 用户 ID (PK)
  • 公司(PK)
  • 用户名
  • 地址...等

而我只想检索当前公司的用户(用户可以通过UI更改公司,所以公司是运行时参数)

同样有很多其他的表结构类似,公共列(公司),我想把数据限制在当前公司,所以我使用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", 参数 = {@org.hibernate.annotations.ParamDef( 名称 = “currentCompanyNumber”,类型 = “int” ) } ) @实体 @表(名称=“用户”) @org.hibernate.annotations.Filter( name = "restrictToCurrentCompany", 条件="公司 = :currentCompanyNumber" ) 公共类用户实现可序列化{ 私人国际公司; 私人字符串用户名; ...等等.. }

道的:

@Repository @Transactional(readOnly = true) 公共类 UserDAOImpl 实现 UserDAO { @Autowired(必需 = 真) 私人 SessionFactory 会话工厂; 公共设置 getUsers(){ .....检索当前公司用户的条件查询 } 私人会话 getSession(){ 返回 sessionFactory.getCurrentSession(); } }

如果我像这样更改 getSession;

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

然后我可以启用过滤器,一切看起来都很好,但是在获取会话期间启用过滤器是否有更简单的替代方法来为整个会话工厂/应用程序级别应用和启用过滤器?如果是这样,我怎么能使用弹簧配置来做到这一点?

我尝试挂接到休眠拦截器(预加载事件侦听器),但我有点不确定这是否是正确的方法,还是我应该使用上面列出的 getSession 方法来启用过滤器?

【问题讨论】:

  • 你最后做了什么,@sachink?同样,我想以一种不那么突兀的方式自动设置我的运行时过滤器值。

标签: hibernate spring hibernate-annotations hibernate-filters


【解决方案1】:

休眠 hbm 文件: 在您的 hbm 文件中声明过滤器。这里filterByFacilityIDs是一个过滤器,facilityIDsParam是一个List类型参数。

<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;
    }

【讨论】:

    【解决方案2】:

    您拥有的解决方案非常简单,但我猜您正在尝试实现它,以便您不必在每个 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 继承它,并在它需要做某事时获得一个会话。这是一种非常简单的方法来做你正在寻找的东西,但它不是万无一失的。如果您正在编写一个供其他人使用的框架,那么什么会阻止他们通过让 Spring 注入来简单地获取对您的 SessionFactory 的引用,然后他们可以获得未过滤的 Session?对于可以对所有数据采取行动的管理流程,您可能希望在某些情况下这样做,但我将描述的下一种方法应该可以防止这种情况发生。

    第二种解决问题的方法是使用 AOP 将 SessionFactory 的 getSession 方法与您的逻辑包装在一起,以便在会话返回之前应用过滤器。这种方法意味着即使有人自己获得了对您的 SessionFactory 的引用,他们仍然会应用此过滤逻辑。

    首先,如果您不熟悉 Spring 中的 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找到这个方法的细节。

    首先,确保您在 spring 的应用程序上下文 XML 中具有以下架构和 aop:config 部分:

    <?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,以实现我们上面使用 aop:aspect 标记引用的 sessionFilterAdvice bean。创建以下类:

    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());
        }
    }
    

    最后要确定的是您的项目包含 spring-aop jar 和 aspectjweaver jar。我不知道您是否使用依赖管理,但您需要以某种方式将这些 jar 放入您的项目类路径中。

    您现在应该能够重新编译您的项目,并且现在对实现 SessionFactory 的类上的任何 openSession 方法的任何调用都会将您的过滤器添加到它们。

    【讨论】:

    • 应该可以在 Spring DI 容器中使用自定义 request scoped 工厂注入适当的过滤Session。但是,这个自定义工厂应该在底层使用 application scoped SessionFactory,因为它的创建是一项非常昂贵的操作。
    猜你喜欢
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 2017-08-04
    • 2015-06-23
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    相关资源
    最近更新 更多