spring 如何为 sessionFactory.getCurrentSession() 启用休眠过滤器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5680750/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to enable hibernate filter for sessionFactory.getCurrentSession()?
提问by sachink
Say there is a User table with structure:
假设有一个具有结构的 User 表:
User
用户
- List item
- userId (PK)
- company (PK)
- userName
- address ...etc
- 项目清单
- 用户 ID (PK)
- 公司(PK)
- 用户名
- 地址...等
And I want to retrieve users only for the current company (company can be changed by the user through UI, so the company is a runtime parameter)
而且我只想检索当前公司的用户(公司可以由用户通过 UI 更改,因此公司是运行时参数)
Similarly there are many other tables that have similar structure with common column (company), and I want to restrict data to only the current company, so I am using hibernate filter to filter out data.
类似的还有很多其他的表,结构相似,有公用列(公司),我想限制数据只到当前公司,所以我用hibernate filter过滤掉数据。
Hibernate annotations:
休眠注释:
<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>
Filter definitions:
过滤器定义:
@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..
}
Dao's:
道:
@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();
}
}
If I change the getSession like so;
如果我像这样更改 getSession ;
private Session getSession(){
Session session = sessionFactory.getCurrentSession();
Filter filter = session.enableFilter("restrictToCurrentCompany");
filter.setParameter("currentCompanyNumber", UserUtils.getCurrentCompany());
return sessionFactory.getCurrentSession();
}
then I can enable the filter and everything looks good, but instead of enabling the filter during getting session is there a simpler alternative to apply and enable filter for the whole session factory/application level? If so, how could I do so using spring configuration?
然后我可以启用过滤器,一切看起来都不错,但是不是在获取会话期间启用过滤器,是否有更简单的替代方法来为整个会话工厂/应用程序级别应用和启用过滤器?如果是这样,我怎么能使用弹簧配置呢?
I tried hooking into hibernate interceptors (pre-load event listerns) but I am bit unsure if this is a correct approach or should I rather use the getSession method listed above to enable filters?
我尝试连接到休眠拦截器(预加载事件侦听器),但我有点不确定这是否是正确的方法,还是应该使用上面列出的 getSession 方法来启用过滤器?
回答by Chris DeLashmutt
The solution you have is pretty simple, but I'm guessing what you are trying for is to make it so that you don't have to provide a "getSession" implementation in each of your DAOs. Ultimately your method of implementing this is going to depend on how flexible you want to be with this filter. Here's two ways I might solve this.
您拥有的解决方案非常简单,但我猜您要尝试的是使其不必在每个 DAO 中都提供“getSession”实现。最终,您实现这一点的方法将取决于您希望使用此过滤器的灵活性。这里有两种方法可以解决这个问题。
The simplest way would be to simply make your UserDAOImpl extend a new base class that contains the "getSession" logic in it. This method would allow you to reduce code in that you would have this filter logic applied in most cases, but then you could override the filtering when you need to.
最简单的方法是简单地让您的 UserDAOImpl 扩展一个包含“getSession”逻辑的新基类。此方法将允许您减少代码,因为您将在大多数情况下应用此过滤器逻辑,但随后您可以在需要时覆盖过滤。
You could create something like this:
你可以创建这样的东西:
public class BaseDAO
{
// ... possibly some other methods and variables
@Autowired(required = true)
private SessionFactory sessionFactory;
protected Session getSession()
{
//Your session filter logic above
}
}
Now you could just have your UserDAOImpl subclass this and get a session when it needs to do something. This is a very simple way to do what you are looking for, but it isn't foolproof. If you are writing a framework for others to use, then what would stop them from simply getting their own reference to your SessionFactory by having Spring inject it and then they could get an unfiltered Session? You might want this in certain circumstances for administrative processes that can act on alldata, but the next way I'll describe should prevent this from happening.
现在你可以让你的 UserDAOImpl 子类化它并在它需要做某事时获得一个会话。这是一种非常简单的方法来执行您正在寻找的操作,但并非万无一失。如果您正在编写一个供其他人使用的框架,那么什么会阻止他们通过让 Spring 注入您的 SessionFactory 来简单地获取自己对您的 SessionFactory 的引用,然后他们可以获得未经过滤的 Session?在某些情况下,对于可以对所有数据进行操作的管理流程,您可能希望这样做,但是我将描述的下一种方法应该可以防止这种情况发生。
This second way to solve the problem involves using AOP to wrap the getSession method of SessionFactory with your logic to apply the filter before the session is returned. This method means that even if someone gets a reference to your SessionFactory themselves, they will still have this filtering logic applied.
第二种解决问题的方法涉及使用 AOP 将 SessionFactory 的 getSession 方法与您的逻辑包装在一起,以便在返回会话之前应用过滤器。此方法意味着即使有人自己获得了对您的 SessionFactory 的引用,他们仍将应用此过滤逻辑。
First, if you aren't familiar with AOP in spring have a look at the reference http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html. I'm going to use the schema based method to apply advice to Hibernate, because we don't want to modify the source of Hibernate. ;) You can find the specifics of this method at http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-schema.
首先,如果您不熟悉 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找到这个方法的细节。
First, make sure you have the following schema and aop:config section in your application context XML for spring:
首先,确保您的 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>
Next, you need to add a bean to your project to implement the sessionFilterAdvice bean we reference above with the aop:aspect tag. Create the following class:
接下来,您需要向您的项目中添加一个 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());
}
}
The final thing to make sure of is that your project includes the spring-aop jar and the aspectjweaver jar. I don't know if you use dependency management or not, but you somehow need to get those jars into your project classpath.
最后要确保的是您的项目包括 spring-aop jar 和 aspectjweaver jar。我不知道你是否使用依赖管理,但你需要以某种方式将这些 jars 放入你的项目类路径中。
You should now be able to recompile your project, and now any calls to any of the openSession methods on classes that implement SessionFactory will add your filter to them.
您现在应该能够重新编译您的项目,现在对实现 SessionFactory 的类上的任何 openSession 方法的任何调用都会将您的过滤器添加到它们中。
回答by Rajib
Hibernate hbm file:Declare filter in your hbm file. Here filterByFacilityIDs is a filter and facilityIDsParam is a List< String > type parameter.
休眠 hbm 文件:在 hbm 文件中声明过滤器。这里 filterByFacilityIDs 是一个过滤器,facilityIDsParam 是一个 List<String> 类型参数。
<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 class **
** 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;
}

