10

次の構造の User テーブルがあるとします。

ユーザー

  • リスト項目
  • ユーザー ID (PK)
  • 会社 (PK)
  • ユーザー名
  • 住所・・・など

そして、現在の会社のユーザーのみを取得したい (会社は UI を介してユーザーが変更できるため、会社はランタイムパラメーターです)

同様に、共通の列 (会社) を持つ同様の構造を持つ他の多くのテーブルがあり、データを現在の会社のみに制限したいので、休止状態フィルターを使用してデータをフィルター処理しています。

休止状態の注釈:

<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(
            名前 = "現在の会社番号"、タイプ = "int"
        )
    }
)
@実在物
@Table(name = "ユーザー")
@org.hibernate.annotations.Filter(
        name = "restrictToCurrentCompany",
        条件="会社 = :現在の会社番号"
)
public class User は Serializable を実装します {
    民間企業;
    プライベート文字列のユーザー名;
    ...等..
}

ダオの:

@リポジトリ
@Transactional(readOnly = true)
public class UserDAOImpl は UserDAO を実装します {

    @Autowired(必須 = true)
    プライベート SessionFactory 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();
}

次に、フィルターを有効にすると、すべてがうまく見えますが、セッションの取得中にフィルターを有効にする代わりに、セッションファクトリー/アプリケーションレベル全体にフィルターを適用して有効にする簡単な方法はありますか? もしそうなら、どうすれば春の設定を使ってそれを行うことができますか?

Hibernate インターセプター (プリロード イベント リスターン) にフックしようとしましたが、これが正しいアプローチなのか、それとも上記の getSession メソッドを使用してフィルターを有効にするべきなのか、少しわかりません。

4

2 に答える 2

19

あなたが持っている解決策は非常に単純ですが、あなたがしようとしているのは、各DAOで「getSession」実装を提供する必要がないようにすることだと思います。最終的にこれを実装する方法は、このフィルターをどの程度柔軟にしたいかによって異なります。これを解決する2つの方法があります。

最も簡単な方法は、「getSession」ロジックを含む新しい基本クラスを UserDAOImpl に拡張させることです。このメソッドを使用すると、ほとんどの場合にこのフィルター ロジックを適用することでコードを削減できますが、必要に応じてフィルター処理をオーバーライドできます。

次のようなものを作成できます。

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 への独自の参照を取得することを阻止し、フィルタリングされていないセッションを取得できるようにするにはどうすればよいでしょうか? 特定の状況では、すべてのデータを処理できる管理プロセスでこれが必要になる場合がありますが、次に説明する方法では、これが発生しないようにする必要があります。

この問題を解決する 2 番目の方法では、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 を追加して、上記で参照した sessionFilterAdvice Bean を 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());
    }
}

最後に確認することは、プロジェクトに spring-aop jar と aspectjweaver jar が含まれていることです。依存関係管理を使用しているかどうかはわかりませんが、何らかの方法でこれらの jar をプロジェクトのクラスパスに入れる必要があります。

これで、プロジェクトを再コンパイルできるようになりました。これで、SessionFactory を実装するクラスで openSession メソッドを呼び出すと、フィルターがそれらに追加されます。

于 2011-08-21T02:45:52.460 に答える
1

Hibernate 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 クラス **

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;
    }
于 2012-07-17T17:54:38.913 に答える