TL;DR:我使用了Hibernate的@Filter,然后创建了一个Aspect来拦截方法
定义了一个具有以下结构的基类实体
OwnerAwareEntity.java
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
@MappedSuperclass
@FilterDef(name = "ownerFilter", parameters = {@ParamDef(name = "ownerRef", type = "long")})
@Filter(name = "ownerFilter", condition = "OWNER_REF = :ownerRef")
public class OwnerAwareEntity implements Serializable{
@Column(name = "OWNER_REF",nullable = true)
private Long ownerRef;
}
我们在这个实体上设置了过滤器。 hibernate @Filter 允许我们设置要附加到 select where 子句的条件。
接下来,为 OwnerAwareEntity 类型的实体定义一个基础存储库
OwnerAwareRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface OwnerAwareRepository<T, ID extends java.io.Serializable> extends JpaRepository<T, ID> {
}
创建了一个切面,它将拦截来自扩展 OwnerAwareRepository 的存储库中的所有方法
OwnerFilterAdvisor.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Filter;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Aspect
@Component
@Slf4j
public class OwnerFilterAdvisor {
@PersistenceContext
private EntityManager entityManager;
@Pointcut("execution(public * com.xyz.app.repository.OwnerAwareRepository+.*(..))")
protected void ownerAwareRepositoryMethod(){
}
@Around(value = "ownerAwareRepositoryMethod()")
public Object enableOwnerFilter(ProceedingJoinPoint joinPoint) throws Throwable{
// Variable holding the session
Session session = null;
try {
// Get the Session from the entityManager in current persistence context
session = entityManager.unwrap(Session.class);
// Enable the filter
Filter filter = session.enableFilter("ownerFilter");
// Set the parameter from the session
filter.setParameter("ownerRef", getSessionOwnerRef());
} catch (Exception ex) {
// Log the error
log.error("Error enabling ownerFilter : Reason -" +ex.getMessage());
}
// Proceed with the joint point
Object obj = joinPoint.proceed();
// If session was available
if ( session != null ) {
// Disable the filter
session.disableFilter("ownerFilter");
}
// Return
return obj;
}
private Long getSessionOwnerRef() {
// Logic to return the ownerRef from current session
}
}
advisor 设置为拦截扩展 OwnerAwareRepository 的类中的所有方法。在拦截时,当前休眠会话是从 entityManager (当前持久性上下文的)中获取的,并且使用“ownerRef”的参数值启用过滤器。
还创建了一个配置文件以扫描顾问程序
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.xyz.app.advisors"})
public class AOPConfig {
}
这些文件到位后,您需要为需要了解所有者的实体完成以下操作
- 实体需要扩展 OwnerAwareEntity
- 实体仓库类需要扩展 OwnerAwareRepository
依赖关系
此设置要求 spring aop 在依赖项中。您可以在 pom.xml 中添加以下内容
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
优势
- 适用于所有选择查询(findBy 方法、findAll 等)
- @Query 方法也会被拦截
- 简单的实现
注意事项
- 删除或更新的where子句不受
这个过滤器。
- 如果存储库包含保存/更新/删除方法并且如果
方法未标记为@Transactional,则拦截器将给出
错误(您可以在这些
中捕获并让该方法正常进行
案例)