7

Dire qu'il ya une table utilisateur avec la structure:Comment activer le filtre Hibernate pour sessionFactory.getCurrentSession()?

utilisateur

  • Liste item
  • userId (PK)
  • entreprise (PK)
  • userName
  • adresse .. .etc

Et je veux récupérer les utilisateurs uniquement pour la société actuelle (la société peut être modifiée par l'utilisateur via l'interface utilisateur, donc la société est un paramètre d'exécution)

De même, il existe de nombreuses autres tables qui ont une structure similaire avec une colonne commune (société), et je veux limiter les données à la seule société actuelle, donc j'utilise le filtre hibernate pour filtrer les données.

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

Définitions Filtre:

 
@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 pour:

 

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

} 

Si je change le getSession comme si;

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

je peux alors activer le filtre et tout semble bon, mais au lieu de permettre au filtre lors de la session d'obtenir est-il une alternative plus simple à appliquer et activer le filtre pour toute usine session/niveau de l'application? Si oui, comment pourrais-je le faire en utilisant la configuration du ressort? J'ai essayé d'accrocher dans les intercepteurs d'hibernation (listerns d'événement de préchargement) mais je ne suis pas certain si c'est une approche correcte ou devrais-je plutôt employer la méthode getSession énumérée ci-dessus pour activer des filtres?

+0

Qu'as vous finissez par faire, @sachink? De même, je veux automatiser mes valeurs de filtre d'exécution d'une manière moins gênante. –

Répondre

14

La solution que vous avez est assez simple, mais je suppose que vous essayez de faire en sorte que vous n'ayez pas à fournir une implémentation "getSession" dans chacun de vos DAO. En fin de compte, votre méthode de mise en œuvre dépendra de la flexibilité avec laquelle vous voulez être avec ce filtre. Voici deux façons de résoudre ce problème.

La méthode la plus simple serait simplement de faire en sorte que UserDAOImpl étende une nouvelle classe de base contenant la logique "getSession". Cette méthode vous permettrait de réduire le code en appliquant cette logique de filtre dans la plupart des cas, mais vous pourriez alors remplacer le filtrage lorsque vous en auriez besoin.

Vous pouvez créer quelque chose comme ceci:

public class BaseDAO 
{ 

    // ... possibly some other methods and variables 

    @Autowired(required = true) 
    private SessionFactory sessionFactory; 

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

Maintenant, vous pouvez simplement avoir votre sous-classe UserDAOImpl cela et une session quand il a besoin de faire quelque chose. C'est une façon très simple de faire ce que vous cherchez, mais ce n'est pas infaillible. Si vous écrivez un framework à utiliser par d'autres, qu'est-ce qui les empêcherait de simplement obtenir leur propre référence à votre SessionFactory en faisant en sorte que Spring l'injecte et qu'ils puissent obtenir une Session non filtrée?Vous voudrez peut-être cela dans certaines circonstances pour les processus administratifs qui peuvent agir sur toutes données, mais la prochaine façon dont je vais décrire devrait empêcher que cela se produise.

Cette deuxième façon de résoudre le problème consiste à utiliser AOP pour envelopper la méthode getSession de SessionFactory avec votre logique pour appliquer le filtre avant la session est renvoyée. Cette méthode signifie que même si quelqu'un obtient une référence à votre SessionFactory, ils auront toujours cette logique de filtrage appliquée.

Tout d'abord, si vous n'êtes pas familier avec AOP au printemps ont un regard sur la référence http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html. Je vais utiliser la méthode basée sur le schéma pour appliquer des conseils à Hibernate, car nous ne voulons pas modifier la source d'Hibernate. ;) Vous pouvez trouver les détails de cette méthode au http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-schema.

Tout d'abord, assurez-vous que le schéma et aop suivant: section de configuration dans votre contexte l'application XML pour le printemps:

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

Ensuite, vous devez ajouter un haricot à votre projet pour mettre en œuvre le haricot sessionFilterAdvice nous référençons ci-dessus avec l'aop: tag d'aspect. Créer la classe suivante:

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

La dernière chose à faire est sûr que votre projet comprend le pot printemps et aop le pot de tissage dans la programmation orientée aspect. Je ne sais pas si vous utilisez la gestion des dépendances ou non, mais vous devez d'une manière ou d'une autre placer ces fichiers dans le classpath de votre projet.

Vous devriez maintenant être en mesure de recompiler votre projet, et maintenant tous les appels à l'une des méthodes openSession sur les classes qui implémentent SessionFactory leur ajouteront votre filtre.

1

Hibernate hbm file: Déclarez le filtre dans votre fichier hbm. Ici filterByFacilityIDs est un filtre et facilityIDsParam est une liste < String> paramètre de 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> 

** classe 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; 
    } 
Questions connexes