如何启用sessionFactory.getCurrentSession()的hibernate过滤器? [英] How to enable hibernate filter for sessionFactory.getCurrentSession()?

查看:130
本文介绍了如何启用sessionFactory.getCurrentSession()的hibernate过滤器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



用户




  • 列表项目

  • userId(PK) userName

  • 地址... etc



我只想检索当前用户公司(公司可以由用户通过UI进行更改,所以公司是一个运行时参数)同样,还有很多其他表与公共列(公司),并且我想限制数据仅限于当前公司,所以我使用hibernate过滤器来过滤数据。



Hibernate注释:

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

< property name =dataSource>
< ref bean =dataSource/>
< / property>
< property name =hibernateProperties>
<道具>
< prop key =hibernate.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>
< /道具>
< / property>
< property name =annotatedClasses>
< list>
<值>用户< /值>
.....
< / list>
< / property>
< / bean>

过滤器定义:

 
@ org.hibernate.annotations.FilterDef(name =restrictToCurrentCompany,
parameters = {@ org.hibernate.annotations.ParamDef(
name =currentCompanyNumber,type =int


$ b @Entity
@Table(name =USER)
@ org.hibernate.annotations.Filter(
$ name =restrictToCurrentCompany,
condition =company =:currentCompanyNumber

public class User实现Serializable {
private int company;
private String userName;
... etc ..
}

Dao's:

 

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

@Autowired = true)
private SessionFactory sessionFactory;
$ b $ public set getUsers(){
.....标准查询检索当前公司的用户
}

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方法来启用过滤器?解决方案

您的解决方案非常简单,但我猜测你想要做的是做到这一点,这样你就不必在每个DAO中提供一个getSession实现。最终,您的实现方法将取决于您希望如何使用此过滤器。这里有两种方法可以解决这个问题。最简单的方法是简单地让UserDAOImpl扩展一个新的基类,其中包含getSession逻辑。这种方法允许你减少代码,因为在大多数情况下你会应用这个过滤器逻辑,但是当你需要的时候你可以覆盖过滤器。



您可以创建如下所示的内容:

  public class BaseDAO 
{

// ...可能还有其他一些方法和变量

@Autowired(required = true)
private SessionFactory sessionFactory;

保护会话getSession()
{
//您的会话过滤逻辑高于
}
}

现在您可以让您的UserDAOImpl子类实现此功能,并在需要执行某些操作时获得会话。这是一种非常简单的方式来做你正在寻找的东西,但它不是万无一失的。如果你正在编写一个框架供其他人使用,那么通过让Spring注入SessionFactory并阻止他们获得他们自己的SessionFactory引用,然后他们可以得到一个未过滤的Session呢?您可能需要在某些情况下针对可以对所有数据执行操作的管理进程,但接下来描述的方式应该防止发生这种情况。



解决问题的第二种方法是使用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

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

 <?xml version =1.0encoding =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 =forceFilterref =sessionFilterAdvice>
< aop:pointcut id =hibernateSessionFactoryGetSession
expression =execution(* org.hibernate.SessionFactory.openSession(..))/>
pointcut-ref =hibernateSessionFactoryGetSessionreturns =session/>
< / aop:aspect>
< / aop:config>

...
< / beans>

接下来,您需要将bean添加到您的项目中,以实现上面引用的sessionFilterAdvice bean aop:方面标签。创建以下类:

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


$ / code $ / pre

最后要确定的是你的项目包括春天的广口瓶和aspectjweaver广口瓶。我不知道你是否使用依赖管理,但你需要将这些jar放入你的项目类路径。



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


Say there is a User table with structure:

User

  • List item
  • userId (PK)
  • company (PK)
  • userName
  • address ...etc

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)

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

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?

解决方案

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.

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.

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 all data, but the next way I'll describe should prevent this from happening.

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.

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.

First, make sure you have the following schema and aop:config section in your application context XML for spring:

<?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:

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.

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.getCurrentSession()的hibernate过滤器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆